From 3887aead06e366e61b6c4c2e88e70dca41991d88 Mon Sep 17 00:00:00 2001 From: Ako Date: Sun, 27 Sep 2026 13:37:52 +0000 Subject: [PATCH 01/13] roundtrip: shard the upgrade property test with MXCLI_UPGRADE_SHARD Round-robin over the scripts that reach execution; every shard still upgrades and checks every script. TestShardsPartition proves the shards together execute each script exactly once. Locally 75+74+75 = 224, the unsharded count. Part of #757. Co-Authored-By: Claude Opus 5.5 --- mdl/roundtrip/shard_test.go | 65 ++++++++++++++++++++++++++ mdl/roundtrip/upgrade_property_test.go | 33 +++++++++++-- mdl/roundtrip/upgrade_shard_test.go | 35 ++++++++++++++ 3 files changed, 128 insertions(+), 5 deletions(-) create mode 100644 mdl/roundtrip/shard_test.go create mode 100644 mdl/roundtrip/upgrade_shard_test.go diff --git a/mdl/roundtrip/shard_test.go b/mdl/roundtrip/shard_test.go new file mode 100644 index 000000000..4d18c3487 --- /dev/null +++ b/mdl/roundtrip/shard_test.go @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: Apache-2.0 + +package roundtrip + +import ( + "fmt" + "testing" +) + +// TestParseShard pins the MXCLI_UPGRADE_SHARD spelling CI passes. +func TestParseShard(t *testing.T) { + for _, tc := range []struct { + in string + i, n int + bad bool + }{ + {in: "", i: 1, n: 1}, + {in: "1/1", i: 1, n: 1}, + {in: "2/3", i: 2, n: 3}, + {in: " 3/3 ", i: 3, n: 3}, + {in: "0/3", bad: true}, + {in: "4/3", bad: true}, + {in: "1/0", bad: true}, + {in: "3", bad: true}, + {in: "a/b", bad: true}, + {in: "1/2/3", bad: true}, + } { + s, err := parseShard(tc.in) + if tc.bad { + if err == nil { + t.Errorf("parseShard(%q) = %+v, want an error", tc.in, s) + } + continue + } + if err != nil || s.index != tc.i || s.count != tc.n { + t.Errorf("parseShard(%q) = %+v, %v; want %d/%d", tc.in, s, err, tc.i, tc.n) + } + } +} + +// TestShardsPartition: CI runs the shards as separate jobs and never the +// unsharded test, so the shards together must execute every script exactly +// once. A script in no shard would silently leave per-PR CI. +func TestShardsPartition(t *testing.T) { + for n := 1; n <= 7; n++ { + const items = 101 + seen := make([]int, items) + for i := 1; i <= n; i++ { + s, err := parseShard(fmt.Sprintf("%d/%d", i, n)) + if err != nil { + t.Fatal(err) + } + for k := 0; k < items; k++ { + if s.has(k) { + seen[k]++ + } + } + } + for k, c := range seen { + if c != 1 { + t.Fatalf("n=%d: item %d is in %d shards, want exactly 1", n, k, c) + } + } + } +} diff --git a/mdl/roundtrip/upgrade_property_test.go b/mdl/roundtrip/upgrade_property_test.go index 0ef29a964..fe508c0fc 100644 --- a/mdl/roundtrip/upgrade_property_test.go +++ b/mdl/roundtrip/upgrade_property_test.go @@ -56,7 +56,12 @@ import ( // Executing the whole corpus takes about 15 minutes, which on its own exceeds // what the CI integration step has left (ako/mxcli#742 timed out there). // MXCLI_UPGRADE_ALL=1 executes every script, header-only ones included; run it -// when a langver.Change or a gated rewrite lands. +// when a langver.Change or a gated rewrite lands. The nightly workflow runs it. +// +// MXCLI_UPGRADE_SHARD=i/n executes only every n-th executable script, starting +// at the i-th, so per-PR CI can split the executions across parallel jobs +// (ako/mxcli#757); the shards together execute each script exactly once +// (TestShardsPartition). Unset is the whole set. func TestUpgradeExecutesToTheSameModel(t *testing.T) { a, b := newHarness(t), newHarness(t) defer a.close() @@ -64,7 +69,12 @@ func TestUpgradeExecutesToTheSameModel(t *testing.T) { scripts := upgradeExampleScripts(t) all := os.Getenv("MXCLI_UPGRADE_ALL") != "" - var same, outOfScope, unparsed, headerOnly, keptVersion []string + sh, err := parseShard(os.Getenv("MXCLI_UPGRADE_SHARD")) + if err != nil { + t.Fatal(err) + } + executable := 0 // scripts that reached execution, in every shard + var same, outOfScope, unparsed, headerOnly, keptVersion, otherShard []string for _, path := range scripts { src, err := os.ReadFile(path) if err != nil { @@ -100,6 +110,14 @@ func TestUpgradeExecutesToTheSameModel(t *testing.T) { headerOnly = append(headerOnly, rel) return } + // Every shard upgrades and checks every script above, which is + // cheap; only the execution below, which is not, is split. + k := executable + executable++ + if !sh.has(k) { + otherShard = append(otherShard, rel) + return + } errA, errB, diff := executeBoth(t, a, b, string(src), res.Source) if len(diff) > 0 { @@ -120,6 +138,10 @@ func TestUpgradeExecutesToTheSameModel(t *testing.T) { } t.Logf("%d scripts execute on PedApp and upgrade to the same model", len(same)) + if sh.count > 1 { + t.Logf("shard %s: %d of %d executable scripts belong to other shards and were not executed here", + sh, len(otherShard), executable) + } t.Logf("%d scripts are out of scope: their original does not execute cleanly on PedApp:\n %s", len(outOfScope), strings.Join(outOfScope, "\n ")) if !all { @@ -130,10 +152,11 @@ func TestUpgradeExecutesToTheSameModel(t *testing.T) { len(keptVersion), strings.Join(keptVersion, "\n ")) t.Logf("%d scripts do not parse (negative tests) and cannot be upgraded:\n %s", len(unparsed), strings.Join(unparsed, "\n ")) - if os.Getenv("MXCLI_UPGRADE_EXAMPLES") == "" && len(same) < 50 { + if floor := 50 / sh.count; os.Getenv("MXCLI_UPGRADE_EXAMPLES") == "" && len(same) < floor { // Hundreds execute today; a handful means the harness broke, and a - // property checked on nothing passes. - t.Errorf("only %d scripts executed cleanly — the harness is not exercising the property", len(same)) + // property checked on nothing passes. A shard sees 1/n of them. + t.Errorf("only %d scripts executed cleanly (shard %s) — the harness is not exercising the property", + len(same), sh) } } diff --git a/mdl/roundtrip/upgrade_shard_test.go b/mdl/roundtrip/upgrade_shard_test.go new file mode 100644 index 000000000..69778d2d0 --- /dev/null +++ b/mdl/roundtrip/upgrade_shard_test.go @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: Apache-2.0 + +package roundtrip + +import ( + "fmt" + "strconv" + "strings" +) + +// shard selects every count-th item starting at index-1: MXCLI_UPGRADE_SHARD +// ("i/n", 1-based) splits the upgrade property test's executions across CI +// jobs (ako/mxcli#757). Round-robin rather than contiguous ranges, because +// the corpus is sorted by path and neighbouring scripts cost alike. +type shard struct{ index, count int } + +// parseShard reads "i/n"; empty is the whole set, 1/1. +func parseShard(s string) (shard, error) { + s = strings.TrimSpace(s) + if s == "" { + return shard{1, 1}, nil + } + a, b, ok := strings.Cut(s, "/") + i, errI := strconv.Atoi(a) + n, errN := strconv.Atoi(b) + if !ok || errI != nil || errN != nil || n < 1 || i < 1 || i > n { + return shard{}, fmt.Errorf("MXCLI_UPGRADE_SHARD=%q: want i/n with 1 <= i <= n", s) + } + return shard{i, n}, nil +} + +// has reports whether the k-th item (0-based) belongs to this shard. +func (s shard) has(k int) bool { return k%s.count == s.index-1 } + +func (s shard) String() string { return fmt.Sprintf("%d/%d", s.index, s.count) } From 4cca3ad14859f5ef92299c009fda133ec89b8c9c Mon Sep 17 00:00:00 2001 From: Ako Date: Sun, 27 Sep 2026 13:37:52 +0000 Subject: [PATCH 02/13] ci: split integration tests into parallel suites; full upgrade corpus nightly The single make test-integration step took ~22 of its 30 minutes, its wall time being mdl/roundtrip alone. Per-PR CI now runs executor, roundtrip, upgrade (3 shards) and other as parallel jobs, with an integration-passed aggregate. Nightly raises its step to 60 min and runs MXCLI_UPGRADE_ALL in 3 shards once. Closes #757. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/nightly.yml | 44 ++++++++++++++- .github/workflows/push-test.yml | 97 ++++++++++++++++++++++++++++++--- Makefile | 44 ++++++++++++++- 3 files changed, 174 insertions(+), 11 deletions(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 14a26cb78..d30612c0c 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -54,9 +54,51 @@ jobs: - name: Setup mxbuild ${{ matrix.mendix-version }} run: ./bin/mxcli setup mxbuild --version ${{ matrix.mendix-version }} + # One step, every package: go test runs the packages in parallel, so the + # wall time is the slowest one's (mdl/roundtrip, ~21 min on this runner in + # ako/mxcli#757's measurement) and grows as the round trip gains fixtures. + # Per-PR CI splits this into parallel jobs instead (push-test.yml). - name: "Integration tests (Mendix ${{ matrix.mendix-version }})" run: make test-integration - timeout-minutes: 30 + timeout-minutes: 60 + + # The upgrade property test over the WHOLE mdl-examples corpus, header-only + # scripts included (MXCLI_UPGRADE_ALL). Per-PR CI executes only the scripts + # the upgrade rewrites beyond the header and terminators; this is the run that + # proves langver's gating on the rest (ako/mxcli#757). Independent of the + # Mendix version — it runs on the committed PedApp fixture and never calls + # mx — so it runs once, not per matrix entry. It does not gate the release. + upgrade-full-corpus: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + shard: ['1/3', '2/3', '3/3'] + name: upgrade full corpus (${{ matrix.shard }}) + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-go@v7 + with: + go-version: '1.26.6' + - name: Cache ANTLR4 JAR + uses: actions/cache@v6 + with: + path: ~/.m2/repository/org/antlr/antlr4 + key: antlr4-4.13.2 + - name: Install ANTLR4 + run: pip install 'antlr4-tools==0.2.2' + - name: Generate parser + run: make grammar + env: + ANTLR4_TOOLS_ANTLR_VERSION: '4.13.2' + - name: Build + run: make build + - name: Upgrade property test, full corpus (${{ matrix.shard }}) + run: make test-integration-upgrade + env: + MXCLI_UPGRADE_ALL: '1' + MXCLI_UPGRADE_SHARD: ${{ matrix.shard }} + timeout-minutes: 45 nightly: needs: test diff --git a/.github/workflows/push-test.yml b/.github/workflows/push-test.yml index 262c5d23f..1d5f323fe 100644 --- a/.github/workflows/push-test.yml +++ b/.github/workflows/push-test.yml @@ -167,17 +167,98 @@ jobs: run: ./scripts/check-skill-mdl.sh ./bin/mxcli .claude/skills/mendix - name: Check docs-site MDL blocks run: ./scripts/check-skill-mdl.sh ./bin/mxcli docs-site/src - - name: Setup mxbuild - run: ./bin/mxcli setup mxbuild --version 11.12.2 - # One engine since the legacy sdk/mpr backend was deleted - # (docs/plans/2026-09-14-retire-legacy-engine.md), so there is no matrix to - # narrow here any more and MXCLI_TEST_ENGINES is left unset. - - name: Integration tests - run: make test-integration - timeout-minutes: 30 + # The integration tests are the `integration` job below. - name: Lint Go run: make lint-go - name: Vulnerability scan run: | go install golang.org/x/vuln/cmd/govulncheck@latest govulncheck ./... + + # The integration tests, split into suites that run as parallel jobs + # (ako/mxcli#757). As one `make test-integration` step they took ~22 of its 30 + # minutes once the upgrade property test landed, and the step's wall time was + # mdl/roundtrip's alone (~21 min) — go test already ran the packages in + # parallel, so no timeout below 30 min was going to hold as the round trip + # grows (#743 adds TestApp to it). + # + # Measured per package on the ubuntu runner (run 36319810164) and what each + # suite is expected to take, including ~3 min of checkout/build/mxbuild: + # executor mdl/executor ~15.5 min -> ~19 min + # roundtrip mdl/roundtrip, round-trip laws ~1.7 min -> ~4 min + # upgrade upgrade property test, 3 shards ~19 min -> ~10 min each + # other cmd/mxcli{,/docker,/marketplace} ~5.7 min -> ~8 min + # The full-corpus upgrade run (MXCLI_UPGRADE_ALL) is nightly, not here. + # + # Nothing here is dropped from per-PR CI: the round-trip laws and the + # execute-both upgrade test run at their default scope, the shards together + # executing every script exactly once (TestShardsPartition). Only the unit + # tests of packages WITHOUT integration tests are no longer re-run under the + # tag — `make test` in build-and-test runs those. + integration: + name: integration (${{ matrix.suite }}${{ matrix.shard && format(' {0}', matrix.shard) || '' }}) + runs-on: ubuntu-latest + # Each suite's go test has its own -timeout (Makefile); this is the job's + # backstop, with room for the setup steps. + timeout-minutes: 45 + strategy: + fail-fast: false + matrix: + include: + - suite: executor + mxbuild: true + - suite: roundtrip + - suite: upgrade + shard: 1/3 + - suite: upgrade + shard: 2/3 + - suite: upgrade + shard: 3/3 + - suite: other + mxbuild: true + steps: + # #743 adds TestApp as a git submodule to the round trip; its checkout + # will need `submodules: true` here for the roundtrip suite. + - uses: actions/checkout@v7 + - uses: actions/setup-go@v7 + with: + go-version: '1.26.6' + - name: Cache ANTLR4 JAR + uses: actions/cache@v6 + with: + path: ~/.m2/repository/org/antlr/antlr4 + key: antlr4-4.13.2 + - name: Install ANTLR4 + run: pip install 'antlr4-tools==0.2.2' + - name: Generate parser + run: make grammar + env: + ANTLR4_TOOLS_ANTLR_VERSION: '4.13.2' + - name: Build + run: make build + # mdl/roundtrip runs on the committed PedApp fixture and never calls mx. + # One engine since the legacy sdk/mpr backend was deleted + # (docs/plans/2026-09-14-retire-legacy-engine.md), so MXCLI_TEST_ENGINES + # is left unset. + - name: Setup mxbuild + if: matrix.mxbuild + run: ./bin/mxcli setup mxbuild --version 11.12.2 + - name: Integration tests (${{ matrix.suite }}) + run: make test-integration-${{ matrix.suite }} + env: + MXCLI_UPGRADE_SHARD: ${{ matrix.shard }} + timeout-minutes: 30 + + # One stable check name for "every integration suite passed", whatever the + # matrix above becomes — a branch rule can require this instead of each leg. + integration-passed: + if: always() + needs: integration + runs-on: ubuntu-latest + steps: + - name: All integration suites passed + run: | + if [ "${{ needs.integration.result }}" != "success" ]; then + echo "integration: ${{ needs.integration.result }}" + exit 1 + fi diff --git a/Makefile b/Makefile index ba84eece8..8a9792fd1 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ GO_BUILD_FLAGS = -trimpath # Clean version for VS Code extension (must be valid semver: major.minor.patch) VSCE_VERSION = $(shell echo "$(VERSION)" | sed 's/^v//; s/-.*//' | grep -E '^[0-9]+\.[0-9]+\.[0-9]+$$' || echo "0.0.0") -.PHONY: build build-debug size release clean test test-mdl check-mdl check-skill-mdl check-skill-pack-js check-findings check-wiki-pages digest-status check-tunnel-deps check-widget-versions grammar completions sync-skills sync-skill-packs sync-commands sync-lint-rules sync-changelog sync-all docs documentation docs-site docs-serve vscode-ext vscode-install source-tree sbom sbom-report lint lint-go lint-ts fmt fmt-check vet +.PHONY: build build-debug size release clean test test-mdl check-mdl check-skill-mdl check-skill-pack-js check-findings check-wiki-pages digest-status check-tunnel-deps check-widget-versions test-integration test-integration-executor test-integration-roundtrip test-integration-upgrade test-integration-other grammar completions sync-skills sync-skill-packs sync-commands sync-lint-rules sync-changelog sync-all docs documentation docs-site docs-serve vscode-ext vscode-install source-tree sbom sbom-report lint lint-go lint-ts fmt fmt-check vet # Helper: copy file only if content differs (avoids mtime updates that invalidate go build cache) # Usage: $(call copy-if-changed,src,dst) @@ -313,7 +313,47 @@ check-tunnel-deps: # therefore left unset everywhere; it survives only so that a stale # `MXCLI_TEST_ENGINES=legacy` is fatal rather than silently selecting nothing. test-integration: - CGO_ENABLED=0 go test -tags integration -count=1 -timeout 30m ./... + CGO_ENABLED=0 go test -tags integration -count=1 -timeout 60m ./... + +# The same integration tests split into suites that CI runs as parallel jobs +# (ako/mxcli#757): one step running them all spent ~22 of its 30 minutes once +# the upgrade property test landed, with mdl/roundtrip alone the critical path. +# +# Unlike test-integration, the suites run only the packages that HAVE +# integration-tagged tests. Every other package's tests are identical with and +# without the tag, and `make test` already runs them. +# +# test-integration-executor mdl/executor: doctype scripts through exec + mx check +# test-integration-roundtrip mdl/roundtrip: the round-trip laws, the upgrade controls +# test-integration-upgrade mdl/roundtrip: the upgrade property test alone; +# MXCLI_UPGRADE_SHARD=i/n runs one of n shards, +# MXCLI_UPGRADE_ALL=1 the full corpus (nightly) +# test-integration-other every other package with integration tests, +# found by build tag so a new one cannot be missed +# (hidden dirs are skipped: nested worktrees live there) +# +# `-skip` / `-run` split mdl/roundtrip by test name, so a new round-trip test +# lands in the roundtrip suite without editing this file. +INTEGRATION_PKGS = $(shell grep -rl --include='*_test.go' --exclude-dir='.?*' --exclude-dir=reference --exclude-dir=mx-test-projects \ + '^//go:build.*integration' . | xargs -n1 dirname | sed 's|^\./||; s|^|./|' | sort -u) +INTEGRATION_SPLIT = ./mdl/executor ./mdl/roundtrip +UPGRADE_PROPERTY = ^TestUpgradeExecutesToTheSameModel$$ +INTEGRATION_GO_TEST = CGO_ENABLED=0 go test -tags integration -count=1 + +test-integration-executor: + $(INTEGRATION_GO_TEST) -timeout 40m ./mdl/executor/ + +test-integration-roundtrip: + $(INTEGRATION_GO_TEST) -timeout 40m -skip '$(UPGRADE_PROPERTY)' ./mdl/roundtrip/ + +test-integration-upgrade: + $(INTEGRATION_GO_TEST) -timeout 40m -run '$(UPGRADE_PROPERTY)' ./mdl/roundtrip/ + +test-integration-other: + @pkgs="$(filter-out $(INTEGRATION_SPLIT),$(INTEGRATION_PKGS))"; \ + if [ -z "$$pkgs" ]; then echo "no integration packages outside the split suites"; exit 1; fi; \ + echo "integration packages: $$pkgs"; \ + $(INTEGRATION_GO_TEST) -timeout 40m $$pkgs # Run MDL integration tests (requires Docker and a Mendix project) # Usage: make test-mdl MPR=path/to/app.mpr From 9c09b4cb6f6775732c641f6d9c063656e8158677 Mon Sep 17 00:00:00 2001 From: Ako Date: Sun, 27 Sep 2026 14:39:35 +0000 Subject: [PATCH 03/13] fix(domain model): keep LocalizeDate and external-entity mappings on rewrite (#743) On the Studio Pro-authored ako/TestApp, running an entity's describe output changed more than the entity: - every DateTime attribute of the rewritten domain model lost LocalizeDate: the writer never set it and the reader never read it. The reader maps an absent LocalizeDate to true (Mendix's default, and what mxcli wrote until now), and producers that do not know it set true; - an external entity's Rest$ODataKey Parts list went from marker 2 (what Studio Pro writes) to 3; - `create or modify external entity`, in both forms, rebuilt each attribute without its OData mapping, so Rest$ODataMappedValue became a plain StoredValue; the `from odata client` form also re-minted attribute $IDs. The rewrite now carries, by name, the mapping, the mapped design-time default and LocalizeDate (carryStoredAttributeState); - describe external entity printed `String` for a String(36), which executes as unlimited. Co-Authored-By: Claude Opus 5.5 --- .../fix-issue/findings/mdl-backend.jsonl | 1 + api/domainmodels.go | 2 + mdl/backend/mcp/read_router.go | 3 +- mdl/backend/modelsdk/domainmodel.go | 20 ++- mdl/backend/modelsdk/domainmodel_write.go | 17 ++- mdl/backend/modelsdk/localize_date_test.go | 87 ++++++++++++ mdl/backend/modelsdk/odata_key_marker_test.go | 45 +++++++ mdl/backend/modelsdk/system_module_read.go | 2 +- mdl/executor/cmd_contract.go | 5 +- mdl/executor/cmd_entities.go | 45 +++++++ mdl/executor/cmd_odata.go | 17 ++- mdl/executor/cmd_odata_mock_test.go | 59 +++++++++ ...ity_modify_carries_attribute_state_test.go | 124 ++++++++++++++++++ 13 files changed, 421 insertions(+), 6 deletions(-) create mode 100644 mdl/backend/modelsdk/localize_date_test.go create mode 100644 mdl/backend/modelsdk/odata_key_marker_test.go create mode 100644 mdl/executor/entity_modify_carries_attribute_state_test.go diff --git a/.claude/skills/fix-issue/findings/mdl-backend.jsonl b/.claude/skills/fix-issue/findings/mdl-backend.jsonl index 0678e5408..05b065e86 100644 --- a/.claude/skills/fix-issue/findings/mdl-backend.jsonl +++ b/.claude/skills/fix-issue/findings/mdl-backend.jsonl @@ -137,3 +137,4 @@ {"area": "mdl/backend", "date": "2026-09-26", "symptom": "describe → exec of a snippet turns its Type 'Web' into '' (and would reset a non-default ExportLevel or canvas size)", "cause": "snippetToGen wrote Type, ExportLevel, CanvasWidth and CanvasHeight as constants on every write; the Type constant was \"\"", "file": "mdl/backend/modelsdk/snippet_write.go", "insight": "The snippet twin of #541 (carryStoredPageHeader). \"\" is not a member of PagesType (Native | Web), so every snippet mxcli created was also invalid. Carry the stored header on UpdateSnippet (width-agnostic canvas read — Studio Pro stores int64); a new snippet gets Web/Hidden/800×600, measured on all four Blank-template snippets", "refs": ["ako/mxcli#705", "#541"]} {"area": "mdl/backend", "date": "2026-09-26", "symptom": "describe → exec of a nanoflow detaches every annotation from its activity (AnnotationFlows 3 → 0, so the next describe prints the notes as free-floating) and deletes ExportLevel, UseListParameterByReference and ReturnVariableName; MarkAsUsed is cleared. Rules drop their annotation flows too", "cause": "nanoflowToGen and ruleToGen never wrote ObjectCollection.AnnotationFlows (microflowToGen did), and nanoflowToGen never set the three header keys; nanoflowFromGen did not read ReturnVariableName or MarkAsUsed and the builder hardcoded MarkAsUsed false", "file": "mdl/backend/modelsdk/nanoflow_write.go, rule_write.go, microflow.go; mdl/executor/cmd_microflows_build.go", "insight": "Three flow flavours share the object/flow converters but each has its own top-level writer, and each dropped a different subset — grep every *ToGen for the same list loop, not just the reported one. For keys with no MDL spelling and unknown version floors (Nanoflow.ExportLevel, UseListParameterByReference), carry ONLY the keys the stored unit has: nothing was ever written on create, Studio Pro fills an absent key, and an undeclared one makes the unit unopenable", "refs": ["ako/mxcli#705"]} {"area": "mdl/backend", "date": "2026-09-27", "symptom": "Running unchanged `describe user role` output (create or modify user role) rewrites Security$ProjectSecurity: /UserRoles[0] marker 2 -> 3; same for DemoUsers on a demo-user rewrite", "cause": "The encoder's default PartList marker is 3; Studio Pro writes 2 for ProjectSecurity.UserRoles and .DemoUsers (PedApp, TestApp, expr-checker agree). An untouched list passes through raw, so it only shows once an element in it is rewritten", "file": "mdl/backend/modelsdk/security_write.go", "insight": "A marker bug hides until the first rewrite of an element in that list; census the stored marker per (owner $Type, key) across Studio Pro fixtures and register it with RegisterPropertyListMarker", "refs": ["ako/mxcli#731"]} +{"area": "mdl/backend", "date": "2026-09-27", "symptom": "Any write of a domain model (even rewriting a sibling entity) drops LocalizeDate from every DateTime attribute in the unit; external entity rewrites also rewrite Source/Key/Parts marker 2 -> 3", "cause": "attributeTypeToGen emitted DateTimeAttributeType without LocalizeDate and attributeTypeFromGen never read it; Rest$ODataKeyPart had no registered list marker so the encoder default 3 applied", "file": "mdl/backend/modelsdk/domainmodel.go, domainmodel_write.go", "insight": "A whole-unit rewrite re-serializes every sibling from the struct, so a property the struct cannot hold is lost on EVERY entity of the module, not just the edited one. Absent LocalizeDate means Mendix's default true (mxcli wrote it absent for years), so the reader must map absent to true or the fix would unlocalize every mxcli-authored DateTime. Only a Studio Pro fixture with DateTime attributes (TestApp) shows it", "refs": ["ako/mxcli#743"]} diff --git a/api/domainmodels.go b/api/domainmodels.go index 32e0b3406..de1b0de39 100644 --- a/api/domainmodels.go +++ b/api/domainmodels.go @@ -305,6 +305,7 @@ func (b *EntityBuilder) WithDateTimeAttribute(name string) *EntityBuilder { ID: generateID(), TypeName: "DomainModels$DateTimeAttributeType", }, + LocalizeDate: true, // Mendix's default; written explicitly since #743 }, } b.attributes = append(b.attributes, attr) @@ -674,6 +675,7 @@ func (b *AttributeBuilder) DateTime() *AttributeBuilder { ID: generateID(), TypeName: "DomainModels$DateTimeAttributeType", }, + LocalizeDate: true, // Mendix's default; written explicitly since #743 } return b } diff --git a/mdl/backend/mcp/read_router.go b/mdl/backend/mcp/read_router.go index 50c01cff4..633fd4806 100644 --- a/mdl/backend/mcp/read_router.go +++ b/mdl/backend/mcp/read_router.go @@ -253,7 +253,8 @@ func attributeTypeFromPED(raw json.RawMessage) domainmodel.AttributeType { case "DomainModels$BooleanAttributeType": return &domainmodel.BooleanAttributeType{} case "DomainModels$DateTimeAttributeType": - return &domainmodel.DateTimeAttributeType{} + // Mendix's default; the payload does not carry LocalizeDate (#743). + return &domainmodel.DateTimeAttributeType{LocalizeDate: true} case "DomainModels$AutoNumberAttributeType": return &domainmodel.AutoNumberAttributeType{} case "DomainModels$BinaryAttributeType": diff --git a/mdl/backend/modelsdk/domainmodel.go b/mdl/backend/modelsdk/domainmodel.go index 62fb15356..4d7d356d3 100644 --- a/mdl/backend/modelsdk/domainmodel.go +++ b/mdl/backend/modelsdk/domainmodel.go @@ -326,6 +326,11 @@ func attributeFromGen(a *genDm.Attribute) *domainmodel.Attribute { // "Attribute 'year' of external entity 'Stg_Season' is not supported." attr.RemoteName = v.RemoteName() attr.RemoteType = v.RemoteType() + // The design-time default is the mapped value's own; without it a + // rewrite writes it empty (Studio Pro stores "false" on a Boolean, #743). + if d := v.DefaultValueDesignTime(); d != "" { + attr.Value = &domainmodel.AttributeValue{DefaultValue: d} + } attr.Filterable = v.Filterable() attr.Sortable = v.Sortable() attr.Creatable = v.Creatable() @@ -526,6 +531,19 @@ func odataKeyFromGen(key element.Element) []*domainmodel.RemoteKeyPart { return parts } +// storedLocalizeDate reads DateTimeAttributeType.LocalizeDate. An absent property +// is Mendix's default, true: mxcli wrote DateTime attributes without it until +// #743, and reading those as false would unlocalize them on the next write of +// their domain model. +func storedLocalizeDate(at *genDm.DateTimeAttributeType) bool { + if raw := at.Raw(); raw != nil { + if _, err := raw.LookupErr("LocalizeDate"); err != nil { + return true + } + } + return at.LocalizeDate() +} + func attributeTypeFromGen(t element.Element) domainmodel.AttributeType { switch at := t.(type) { case *genDm.StringAttributeType: @@ -539,7 +557,7 @@ func attributeTypeFromGen(t element.Element) domainmodel.AttributeType { case *genDm.BooleanAttributeType: return &domainmodel.BooleanAttributeType{} case *genDm.DateTimeAttributeType: - return &domainmodel.DateTimeAttributeType{} + return &domainmodel.DateTimeAttributeType{LocalizeDate: storedLocalizeDate(at)} case *genDm.AutoNumberAttributeType: return &domainmodel.AutoNumberAttributeType{} case *genDm.BinaryAttributeType: diff --git a/mdl/backend/modelsdk/domainmodel_write.go b/mdl/backend/modelsdk/domainmodel_write.go index 3b477f208..0fef7bd67 100644 --- a/mdl/backend/modelsdk/domainmodel_write.go +++ b/mdl/backend/modelsdk/domainmodel_write.go @@ -699,7 +699,15 @@ func attributeTypeToGen(t domainmodel.AttributeType) element.Element { return genDm.NewDecimalAttributeType() case *domainmodel.BooleanAttributeType: return genDm.NewBooleanAttributeType() - case *domainmodel.DateTimeAttributeType, *domainmodel.DateAttributeType: + case *domainmodel.DateTimeAttributeType: + // Always written: a domain-model write re-serializes every entity in the + // unit, so leaving it out dropped a Studio Pro-authored LocalizeDate on + // every rewrite (#743). Producers that do not know it set true, Mendix's + // default and what an absent property meant before. + g := genDm.NewDateTimeAttributeType() + g.SetLocalizeDate(at.LocalizeDate) + return g + case *domainmodel.DateAttributeType: return genDm.NewDateTimeAttributeType() case *domainmodel.AutoNumberAttributeType: return genDm.NewAutoNumberAttributeType() @@ -757,6 +765,13 @@ func externalEntitySourceToGen(e *domainmodel.Entity) element.Element { return nil } +func init() { + // An external entity's Rest$ODataKey Parts list is marker 2 in Studio Pro's + // BSON (measured on ako/TestApp, Clients.Orders); the default 3 rewrote the + // key on every domain-model write (#743). + codec.RegisterListMarker("Rest$ODataKeyPart", 2) +} + // odataKeyToGen builds a Rest$ODataKey from the entity's remote key parts, or nil // when there are none. func odataKeyToGen(parts []*domainmodel.RemoteKeyPart) element.Element { diff --git a/mdl/backend/modelsdk/localize_date_test.go b/mdl/backend/modelsdk/localize_date_test.go new file mode 100644 index 000000000..2388e6bf5 --- /dev/null +++ b/mdl/backend/modelsdk/localize_date_test.go @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: Apache-2.0 + +package modelsdkbackend + +import ( + "testing" + + "go.mongodb.org/mongo-driver/v2/bson" + + genDm "github.com/mendixlabs/mxcli/modelsdk/gen/domainmodels" + genRest "github.com/mendixlabs/mxcli/modelsdk/gen/rest" + "github.com/mendixlabs/mxcli/sdk/domainmodel" +) + +// A domain-model write re-serializes every entity in the unit, and the writer +// emitted DateTimeAttributeType without LocalizeDate while the reader never read +// it. On the Studio Pro-authored ako/TestApp every DateTime attribute of a +// rewritten domain model lost its LocalizeDate (#743). + +func TestAttributeTypeToGen_WritesLocalizeDate(t *testing.T) { + for _, want := range []bool{true, false} { + g, ok := attributeTypeToGen(&domainmodel.DateTimeAttributeType{LocalizeDate: want}).(*genDm.DateTimeAttributeType) + if !ok { + t.Fatalf("DateTime maps to %T", g) + } + if g.LocalizeDate() != want { + t.Errorf("LocalizeDate written = %v, want %v", g.LocalizeDate(), want) + } + if !g.IsDirty() { + t.Errorf("LocalizeDate=%v was never set, so the property is left out of the BSON", want) + } + } +} + +func dateTimeTypeFromRaw(t *testing.T, doc bson.D) *genDm.DateTimeAttributeType { + t.Helper() + raw, err := bson.Marshal(doc) + if err != nil { + t.Fatal(err) + } + g := genDm.NewDateTimeAttributeType() + g.SetRaw(raw) + g.InitFromRaw(raw) + return g +} + +func TestAttributeTypeFromGen_ReadsLocalizeDate(t *testing.T) { + for _, stored := range []bool{true, false} { + g := dateTimeTypeFromRaw(t, bson.D{{Key: "$Type", Value: "DomainModels$DateTimeAttributeType"}, {Key: "LocalizeDate", Value: stored}}) + dt, ok := attributeTypeFromGen(g).(*domainmodel.DateTimeAttributeType) + if !ok { + t.Fatalf("read as %T", attributeTypeFromGen(g)) + } + if dt.LocalizeDate != stored { + t.Errorf("LocalizeDate read = %v, stored %v", dt.LocalizeDate, stored) + } + } +} + +// mxcli wrote DateTime attributes without the property until #743, and an absent +// LocalizeDate is Mendix's default, true. Reading it as false would turn every +// such attribute unlocalized on the next write of its domain model. +func TestAttributeTypeFromGen_AbsentLocalizeDateIsTrue(t *testing.T) { + g := dateTimeTypeFromRaw(t, bson.D{{Key: "$Type", Value: "DomainModels$DateTimeAttributeType"}}) + dt, ok := attributeTypeFromGen(g).(*domainmodel.DateTimeAttributeType) + if !ok || !dt.LocalizeDate { + t.Errorf("absent LocalizeDate read as %+v, want true", attributeTypeFromGen(g)) + } +} + +// The mapped value's design-time default is read back, or a domain-model write +// empties it on every external attribute (#743). +func TestAttributeFromGen_ODataMappedDefault(t *testing.T) { + g := genDm.NewAttribute() + g.SetName("Online") + mv := genRest.NewODataMappedValue() + mv.SetRemoteName("Online") + mv.SetDefaultValueDesignTime("false") + g.SetValue(mv) + attr := attributeFromGen(g) + if attr.Value == nil || attr.Value.DefaultValue != "false" { + t.Errorf("default = %+v, want \"false\"", attr.Value) + } + if out, ok := attributeToGen(attr, true).Value().(*genRest.ODataMappedValue); !ok || out.DefaultValueDesignTime() != "false" { + t.Errorf("rewritten value = %+v", attributeToGen(attr, true).Value()) + } +} diff --git a/mdl/backend/modelsdk/odata_key_marker_test.go b/mdl/backend/modelsdk/odata_key_marker_test.go new file mode 100644 index 000000000..1be07a1fe --- /dev/null +++ b/mdl/backend/modelsdk/odata_key_marker_test.go @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: Apache-2.0 + +package modelsdkbackend + +import ( + "testing" + + "go.mongodb.org/mongo-driver/v2/bson" + + "github.com/mendixlabs/mxcli/modelsdk/codec" + "github.com/mendixlabs/mxcli/sdk/domainmodel" +) + +// Studio Pro writes an external entity's Rest$ODataKey Parts list with the +// typed-array marker 2 (measured on the Studio Pro-authored ako/TestApp, +// Clients.Orders); the encoder's default is 3, so every domain-model write +// rewrote the key of every external entity in the unit (#743). +func TestODataKeyToGen_PartsMarkerIsTwo(t *testing.T) { + key := odataKeyToGen([]*domainmodel.RemoteKeyPart{{ + Name: "OrderId", RemoteName: "OrderId", RemoteType: "Edm.Int64", + Type: &domainmodel.LongAttributeType{}, + }}) + b, err := (&codec.Encoder{}).Encode(key) + if err != nil { + t.Fatal(err) + } + var doc bson.D + if err := bson.Unmarshal(b, &doc); err != nil { + t.Fatal(err) + } + for _, e := range doc { + if e.Key != "Parts" { + continue + } + arr, ok := e.Value.(bson.A) + if !ok || len(arr) != 2 { + t.Fatalf("Parts = %v, want [marker, part]", e.Value) + } + if m, ok := arr[0].(int32); !ok || m != 2 { + t.Errorf("Parts marker = %v, want 2", arr[0]) + } + return + } + t.Fatalf("encoded key has no Parts: %v", doc) +} diff --git a/mdl/backend/modelsdk/system_module_read.go b/mdl/backend/modelsdk/system_module_read.go index 912f8ab5d..6787b6d15 100644 --- a/mdl/backend/modelsdk/system_module_read.go +++ b/mdl/backend/modelsdk/system_module_read.go @@ -75,7 +75,7 @@ func systemAttrType(a meta.SystemAttrDef) domainmodel.AttributeType { case "Boolean": return &domainmodel.BooleanAttributeType{} case "DateTime": - return &domainmodel.DateTimeAttributeType{} + return &domainmodel.DateTimeAttributeType{LocalizeDate: true} case "Enumeration": return &domainmodel.EnumerationAttributeType{EnumerationRef: a.EnumQN} case "AutoNumber": diff --git a/mdl/executor/cmd_contract.go b/mdl/executor/cmd_contract.go index eb76b4915..c34006235 100644 --- a/mdl/executor/cmd_contract.go +++ b/mdl/executor/cmd_contract.go @@ -1466,7 +1466,10 @@ func edmToDomainModelAttrType(p *types.EdmProperty, isKey bool) domainmodel.Attr case "Edm.Boolean": return &domainmodel.BooleanAttributeType{} case "Edm.DateTime", "Edm.DateTimeOffset", "Edm.Date": - return &domainmodel.DateTimeAttributeType{} + // LocalizeDate true is what the writer emitted before it wrote the + // property at all (#743), and what Studio Pro stores for an imported + // Edm.DateTimeOffset. + return &domainmodel.DateTimeAttributeType{LocalizeDate: true} case "Edm.Guid": return &domainmodel.StringAttributeType{Length: 36} case "Edm.Binary": diff --git a/mdl/executor/cmd_entities.go b/mdl/executor/cmd_entities.go index e2936f07e..50d3f800a 100644 --- a/mdl/executor/cmd_entities.go +++ b/mdl/executor/cmd_entities.go @@ -484,6 +484,7 @@ func mergeDeclaredOntoStoredEntity(stored, declared *domainmodel.Entity, s *ast. merged.Persistable = declared.Persistable merged.Location = declared.Location merged.Attributes = declared.Attributes + carryStoredAttributeState(stored, merged.Attributes) merged.ValidationRules = mergeValidationRules(stored, declared) merged.Indexes = declared.Indexes merged.EventHandlers = declared.EventHandlers @@ -512,6 +513,50 @@ func mergeDeclaredOntoStoredEntity(stored, declared *domainmodel.Entity, s *ast. return &merged } +// carryStoredAttributeState carries, by attribute name, what the entity body +// has no spelling for onto the attributes the statement rebuilt: an external +// entity attribute's OData mapping (without it the writer emits a plain +// StoredValue and the attribute is no longer mapped to the remote property), and +// a DateTime's LocalizeDate. The attribute set and each declared type stay the +// statement's; LocalizeDate carries only onto a DateTime that stays one (#743). +func carryStoredAttributeState(stored *domainmodel.Entity, declared []*domainmodel.Attribute) { + byName := make(map[string]*domainmodel.Attribute, len(stored.Attributes)) + for _, a := range stored.Attributes { + if a != nil { + byName[a.Name] = a + } + } + for _, a := range declared { + if a == nil { + continue + } + old, ok := byName[a.Name] + if !ok { + continue + } + if old.RemoteName != "" || old.IsPrimitiveCollection { + a.RemoteName = old.RemoteName + a.RemoteType = old.RemoteType + a.Filterable = old.Filterable + a.Sortable = old.Sortable + a.Creatable = old.Creatable + a.Updatable = old.Updatable + a.IsPrimitiveCollection = old.IsPrimitiveCollection + // A mapped attribute's design-time default has no spelling in the + // `from odata client` form, so an undeclared one keeps the stored. + if a.Value == nil && old.Value != nil { + v := *old.Value + a.Value = &v + } + } + if dt, ok := a.Type.(*domainmodel.DateTimeAttributeType); ok { + if odt, ok := old.Type.(*domainmodel.DateTimeAttributeType); ok { + dt.LocalizeDate = odt.LocalizeDate + } + } + } +} + // entityFieldsDeclaredByStatement names the domainmodel.Entity fields that // `create or modify entity` is authoritative about — the ones // mergeDeclaredOntoStoredEntity takes from the rebuilt entity. Every other field diff --git a/mdl/executor/cmd_odata.go b/mdl/executor/cmd_odata.go index b4cd18931..ca2fd4baa 100644 --- a/mdl/executor/cmd_odata.go +++ b/mdl/executor/cmd_odata.go @@ -806,9 +806,11 @@ func outputExternalEntityMDL(ctx *ExecContext, entity *domainmodel.Entity, modul fmt.Fprintln(ctx.Output, ")") fmt.Fprintln(ctx.Output, "(") for i, attr := range entity.Attributes { + // formatAttributeType, not GetTypeName: the bare `String` executes as + // unlimited and rewrote a stored String(36) (#743). typeName := "Unknown" if attr.Type != nil { - typeName = attr.Type.GetTypeName() + typeName = formatAttributeType(attr.Type) } comma := "," if i == len(entity.Attributes)-1 { @@ -909,6 +911,19 @@ func execCreateExternalEntity(ctx *ExecContext, s *ast.CreateExternalEntityStmt) existingEntity.CreateChangeLocally = *s.AllowCreateChangeLocally } if len(attrs) > 0 { + // The rebuilt attributes keep each stored attribute's identity and + // what the statement cannot spell (the OData mapping, LocalizeDate), + // by name; a fresh $ID and a plain StoredValue made the rewrite an + // unmapped attribute (#743). + for _, a := range attrs { + for _, old := range existingEntity.Attributes { + if old.Name == a.Name { + a.ID = old.ID + break + } + } + } + carryStoredAttributeState(existingEntity, attrs) existingEntity.Attributes = attrs } // A rewrite that carried no doc comment keeps the stored one; an diff --git a/mdl/executor/cmd_odata_mock_test.go b/mdl/executor/cmd_odata_mock_test.go index 21364836c..e5e8527ef 100644 --- a/mdl/executor/cmd_odata_mock_test.go +++ b/mdl/executor/cmd_odata_mock_test.go @@ -679,3 +679,62 @@ func TestCreateODataClient_HeadersMicroflow(t *testing.T) { t.Errorf("ConfigurationMicroflow = %q, want empty (headers keyword must not populate the config slot)", captured.ConfigurationMicroflow) } } + +// `create or modify external entity … from odata client … (attrs)` rebuilt each +// attribute with a fresh $ID and no OData mapping, so rerunning `describe +// external entity` output turned every Rest$ODataMappedValue into a plain +// StoredValue (#743). +func TestCreateOrModifyExternalEntity_KeepsAttributeIdentityAndMapping(t *testing.T) { + mod := mkModule("Clients") + h := mkHierarchy(mod) + svc := &model.ConsumedODataService{BaseElement: model.BaseElement{ID: nextID("cos")}, ContainerID: mod.ID, Name: "OrderODataClient"} + withContainer(h, svc.ContainerID, mod.ID) + existing := &domainmodel.Entity{ + BaseElement: model.BaseElement{ID: nextID("ent")}, + Name: "Orders", + Source: "Rest$ODataRemoteEntitySource", + RemoteServiceName: "Clients.OrderODataClient", + RemoteEntitySet: "Orders", + Attributes: []*domainmodel.Attribute{{ + BaseElement: model.BaseElement{ID: "stored-attr-id"}, + Name: "OrderDate", + Type: &domainmodel.DateTimeAttributeType{LocalizeDate: false}, + RemoteName: "OrderDate", RemoteType: "Edm.DateTimeOffset", Filterable: true, Sortable: true, + }}, + } + dm := &domainmodel.DomainModel{BaseElement: model.BaseElement{ID: nextID("dm")}, ContainerID: mod.ID, Entities: []*domainmodel.Entity{existing}} + var updated *domainmodel.Entity + mb := &mock.MockBackend{ + IsConnectedFunc: func() bool { return true }, + ListModulesFunc: func() ([]*model.Module, error) { return []*model.Module{mod}, nil }, + GetDomainModelFunc: func(model.ID) (*domainmodel.DomainModel, error) { return dm, nil }, + ListConsumedODataServicesFunc: func() ([]*model.ConsumedODataService, error) { return []*model.ConsumedODataService{svc}, nil }, + UpdateEntityFunc: func(_ model.ID, e *domainmodel.Entity) error { updated = e; return nil }, + } + ctx, _ := newMockCtx(t, withBackend(mb), withHierarchy(h)) + stmt := &ast.CreateExternalEntityStmt{ + Name: ast.QualifiedName{Module: "Clients", Name: "Orders"}, + ServiceRef: ast.QualifiedName{Module: "Clients", Name: "OrderODataClient"}, + EntitySet: strPtr("Orders"), + Attributes: []ast.Attribute{{Name: "OrderDate", Type: ast.DataType{Kind: ast.TypeDateTime}}, {Name: "Added", Type: ast.DataType{Kind: ast.TypeLong}}}, + CreateOrModify: true, + } + assertNoError(t, execCreateExternalEntity(ctx, stmt)) + if updated == nil || len(updated.Attributes) != 2 { + t.Fatalf("expected an update with two attributes, got %+v", updated) + } + a := updated.Attributes[0] + if a.ID != "stored-attr-id" { + t.Errorf("OrderDate $ID = %q, want the stored one", a.ID) + } + if a.RemoteName != "OrderDate" || a.RemoteType != "Edm.DateTimeOffset" || !a.Filterable || !a.Sortable { + t.Errorf("OrderDate lost its OData mapping: %+v", a) + } + if dt, ok := a.Type.(*domainmodel.DateTimeAttributeType); !ok || dt.LocalizeDate { + t.Errorf("OrderDate LocalizeDate not carried: %+v", a.Type) + } + // Control: a new attribute gets a fresh identity and no mapping. + if b := updated.Attributes[1]; b.ID == "" || b.ID == "stored-attr-id" || b.RemoteName != "" { + t.Errorf("new attribute Added = %+v", b) + } +} diff --git a/mdl/executor/entity_modify_carries_attribute_state_test.go b/mdl/executor/entity_modify_carries_attribute_state_test.go new file mode 100644 index 000000000..36b10e8f8 --- /dev/null +++ b/mdl/executor/entity_modify_carries_attribute_state_test.go @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: Apache-2.0 + +package executor + +import ( + "strings" + "testing" + + "github.com/mendixlabs/mxcli/mdl/ast" + "github.com/mendixlabs/mxcli/model" + "github.com/mendixlabs/mxcli/sdk/domainmodel" +) + +// `create or modify external entity` rebuilt each attribute from the statement, +// and the statement has no words for an attribute's OData mapping or for +// DateTime's LocalizeDate. Running an external entity's own describe output, +// unchanged, on the Studio Pro-authored ako/TestApp turned every attribute's +// Rest$ODataMappedValue into a DomainModels$StoredValue (RemoteName, RemoteType, +// Filterable, ... gone) and dropped LocalizeDate (#743). The attribute SET is +// still the statement's to declare; what it cannot spell is carried by name. + +func storedExternalEntity() *domainmodel.Entity { + return &domainmodel.Entity{ + BaseElement: model.BaseElement{ID: "stored-id"}, + Name: "Orders", + Source: "Rest$ODataRemoteEntitySource", + RemoteServiceName: "Clients.OrderODataClient", + Attributes: []*domainmodel.Attribute{ + { + BaseElement: model.BaseElement{ID: "attr-date"}, + Name: "OrderDate", + Type: &domainmodel.DateTimeAttributeType{LocalizeDate: false}, + RemoteName: "OrderDate", RemoteType: "Edm.DateTimeOffset", + Filterable: true, Sortable: true, Creatable: true, Updatable: true, + }, + { + BaseElement: model.BaseElement{ID: "attr-id"}, + Name: "OrderId", + Type: &domainmodel.LongAttributeType{}, + RemoteName: "OrderId", RemoteType: "Edm.Int64", + Filterable: true, + }, + }, + } +} + +func TestMergeDeclaredOntoStoredEntity_CarriesODataMappingAndLocalizeDate(t *testing.T) { + declared := &domainmodel.Entity{Name: "Orders", Attributes: []*domainmodel.Attribute{ + // What the executor builds from `OrderDate: DateTime, OrderId: Long`. + {Name: "OrderDate", Type: &domainmodel.DateTimeAttributeType{LocalizeDate: true}}, + {Name: "OrderId", Type: &domainmodel.LongAttributeType{}}, + {Name: "Added", Type: &domainmodel.LongAttributeType{}}, + }} + merged := mergeDeclaredOntoStoredEntity(storedExternalEntity(), declared, &ast.CreateEntityStmt{}) + + date := merged.Attributes[0] + if date.RemoteName != "OrderDate" || date.RemoteType != "Edm.DateTimeOffset" || + !date.Filterable || !date.Sortable || !date.Creatable || !date.Updatable { + t.Errorf("OrderDate lost its OData mapping — the writer falls back to a StoredValue: %+v", date) + } + if dt, ok := date.Type.(*domainmodel.DateTimeAttributeType); !ok || dt.LocalizeDate { + t.Errorf("OrderDate LocalizeDate = %v, want the stored false", date.Type) + } + if id := merged.Attributes[1]; id.RemoteName != "OrderId" || id.RemoteType != "Edm.Int64" || !id.Filterable { + t.Errorf("OrderId lost its OData mapping: %+v", id) + } + // Control: an attribute the stored entity does not have gets nothing carried. + if added := merged.Attributes[2]; added.RemoteName != "" { + t.Errorf("a new attribute was given a mapping it never had: %+v", added) + } +} + +// A type the statement changes is the statement's to decide: LocalizeDate only +// carries onto a DateTime that stays a DateTime. +func TestMergeDeclaredOntoStoredEntity_LocalizeDateOnlyCarriesOntoDateTime(t *testing.T) { + stored := &domainmodel.Entity{Name: "E", Attributes: []*domainmodel.Attribute{ + {Name: "When", Type: &domainmodel.DateTimeAttributeType{LocalizeDate: false}}, + }} + declared := &domainmodel.Entity{Name: "E", Attributes: []*domainmodel.Attribute{ + {Name: "When", Type: &domainmodel.StringAttributeType{Length: 20}}, + }} + merged := mergeDeclaredOntoStoredEntity(stored, declared, &ast.CreateEntityStmt{}) + if _, ok := merged.Attributes[0].Type.(*domainmodel.StringAttributeType); !ok { + t.Errorf("the declared type change was overridden: %T", merged.Attributes[0].Type) + } +} + +// A mapped attribute's design-time default (Studio Pro stores "false" on a +// Boolean) has no spelling in the `from odata client` form; an undeclared one +// keeps the stored value, a declared one wins. +func TestCarryStoredAttributeState_MappedDefault(t *testing.T) { + stored := &domainmodel.Entity{Attributes: []*domainmodel.Attribute{ + {Name: "Online", Type: &domainmodel.BooleanAttributeType{}, RemoteName: "Online", Value: &domainmodel.AttributeValue{DefaultValue: "false"}}, + {Name: "Flag", Type: &domainmodel.BooleanAttributeType{}, RemoteName: "Flag", Value: &domainmodel.AttributeValue{DefaultValue: "false"}}, + }} + declared := []*domainmodel.Attribute{ + {Name: "Online", Type: &domainmodel.BooleanAttributeType{}}, + {Name: "Flag", Type: &domainmodel.BooleanAttributeType{}, Value: &domainmodel.AttributeValue{DefaultValue: "true"}}, + } + carryStoredAttributeState(stored, declared) + if declared[0].Value == nil || declared[0].Value.DefaultValue != "false" { + t.Errorf("Online default = %+v, want the stored \"false\"", declared[0].Value) + } + if declared[1].Value.DefaultValue != "true" { + t.Errorf("Flag's declared default was overridden: %+v", declared[1].Value) + } + if declared[0].Value == stored.Attributes[0].Value { + t.Error("the carried value aliases the stored one") + } +} + +// describe external entity printed GetTypeName (`String`), which executes as +// unlimited and rewrote a Studio Pro String(36) (#743). +func TestOutputExternalEntityMDL_PrintsStringLength(t *testing.T) { + ctx, buf := newMockCtx(t) + e := &domainmodel.Entity{Name: "Devices", RemoteServiceName: "Odata.Client", RemoteEntitySet: "Devices", + Attributes: []*domainmodel.Attribute{{Name: "_Id", Type: &domainmodel.StringAttributeType{Length: 36}}}} + if err := outputExternalEntityMDL(ctx, e, "Odata"); err != nil { + t.Fatal(err) + } + if !strings.Contains(buf.String(), "_Id: String(36)") { + t.Errorf("describe lost the length:\n%s", buf.String()) + } +} From 4cc34e02e9dcafdcf715bce87f7b0eae6647c4d4 Mon Sep 17 00:00:00 2001 From: Ako Date: Sun, 27 Sep 2026 14:39:50 +0000 Subject: [PATCH 04/13] fix(odata service): carry what describe cannot print; describe emits create or modify (#743) Running a published service's describe output as `create or modify` over the three Studio Pro-authored services of ako/TestApp: - set every entity set's PageSize 10000 -> 0 (describe prints PageSize only with UsePaging), reordered the entity sets into entity-type order and recomputed each member's CanBeEmpty. The modify path now carries all three from the stored service (carryPublishedEntityState); CanBeEmpty is read and written when stored, and derived from the key as before when not; - deleted ExportLevel: the model had no field. It is read, and written only when stored, so a service mxcli creates is unchanged; - wrote AuthenticationTypes with marker 3. Studio Pro writes 1 on all three; the 3 matched the legacy writer, not Studio Pro. With that the rewrite writes nothing on all three, so describe switches to `create or modify odata service`; the round-trip harness holds it to both laws on TestApp. mx check on a TestApp copy after running the describe output of the three services: 0 errors before and after. Co-Authored-By: Claude Opus 5.5 --- .../fix-issue/findings/mdl-executor.jsonl | 2 + mdl/backend/modelsdk/integration_read.go | 1 + mdl/backend/modelsdk/odata_read_detail.go | 4 + .../modelsdk/odata_service_carry_test.go | 81 +++++++++++++++++++ mdl/backend/modelsdk/odata_write.go | 34 ++++---- mdl/executor/cmd_odata.go | 56 ++++++++++++- mdl/executor/cmd_odata_mock_test.go | 4 +- mdl/executor/cmd_odata_service_carry_test.go | 77 ++++++++++++++++++ model/types.go | 8 ++ 9 files changed, 248 insertions(+), 19 deletions(-) create mode 100644 mdl/backend/modelsdk/odata_service_carry_test.go create mode 100644 mdl/executor/cmd_odata_service_carry_test.go diff --git a/.claude/skills/fix-issue/findings/mdl-executor.jsonl b/.claude/skills/fix-issue/findings/mdl-executor.jsonl index bdafc5486..713002bfb 100644 --- a/.claude/skills/fix-issue/findings/mdl-executor.jsonl +++ b/.claude/skills/fix-issue/findings/mdl-executor.jsonl @@ -733,3 +733,5 @@ {"area": "mdl/executor", "date": "2026-09-27", "symptom": "describe microflow \u2026 with handles printed `-- handle: commit $Order on error {` for an activity with a custom error handler (TestApp Services.SaveOrder). The handle could not be used: an `alter microflow` target ends at the `{` that opens a fragment, so `insert after commit $Order on error { \u2026 }` parsed the handler brace as the fragment.", "cause": "printedStatement ended an action's statement at a line ending in `;` or `{` and kept the `{`, which belongs to the error-handler block describe opens, not to the statement.", "file": "mdl/executor/cmd_microflows_handles.go", "fix": "printedStatement strips the trailing `{` of an error-handler block opener, so the handle is `commit $Order on error`, which parses as a target and still matches the activity.", "insight": "A handle is only useful if it can be written back as a target in the grammar that consumes it; test a printed handle by parsing it, not only by resolving it.", "test": "TestPrintedStatement_ErrorHandlerBlockOpenerIsNotPartOfTheStatement"} {"area": "mdl/executor", "date": "2026-09-27", "symptom": "alter microflow (ako/mxcli#736) reported \"Altered microflow\" for statements mx check then rejected: two fragments in one statement declaring the same variable gave CE0111 Duplicate variable name; a fragment reading $X in the same statement as `drop $X` (either order) gave CE0109 Undefined variable. A loop fragment was refused as reading its own iterator, and drop/replace of a Studio Pro loop with more than one body activity was refused by the dangling-reference guard.", "cause": "The scope checks compared each operation with the flow as stored, never with what earlier operations of the same statement had declared, read or removed. The iterator of a fragment's loop is on its LoopSource, not an action output. Loop body flows are stored in the unit's Flows list, not in the loop, so removing the loop left them pointing at removed objects.", "file": "mdl/executor/cmd_alter_flow.go; mdl/backend/mfmutator/splice.go", "fix": "alterFlowContext tracks declaredByOps / readByOps / removedByOps across the statement's operations and checks each later operation against them; checkFragmentScope counts a fragment loop's iterator as its own; Drop and Replace remove graph.bodyFlows of a loop with it.", "insight": "A per-operation check against the stored document is only sound for a one-operation statement; every multi-operation test needs a case where operation 2 depends on operation 1. mx check on a copied TestApp is the cheap oracle: the CE numbers appear the moment a hygiene hole is hit.", "test": "TestAlterMicroflow_PedApp_ScopeSpansTheStatement; TestAlterMicroflow_PedApp_LoopFragmentDeclaresItsIterator; TestSplice_DropOrReplaceALoopTakesItsBodyFlows"} {"area": "mdl/executor", "date": "2026-09-27", "symptom": "describe of a published REST service with no resources printed `create or modify published rest service M.S ( \u2026 )` followed by a bare `;`, which does not parse (`mismatched input ';' expecting '{'`); found while making describe end every statement with `;` (ako/mxcli#744).", "cause": "The resource block `{ \u2026 }` is mandatory in the grammar (publishedRestService: \u2026 RPAREN LBRACE publishedRestResource* RBRACE), but the describer only printed it when the service had resources and otherwise closed the statement with `;` alone.", "file": "mdl/executor/cmd_published_rest.go", "fix": "Always print the block: `{\\n};` when there are no resources.", "insight": "A describe test that asserts substrings never parses the output; feeding every Describe*_Mock output through the parser (assertTerminated, #744) found this at once. The empty-collection branch of a describer is the one no fixture exercises.", "test": "TestDescribePublishedRestService_Mock (assertTerminated)"} +{"area": "mdl/executor", "date": "2026-09-27", "symptom": "Running an external entity's describe output (create or modify external entity, either form) turns each attribute's Rest$ODataMappedValue into a DomainModels$StoredValue (RemoteName/RemoteType/Filterable... gone), re-mints attribute $IDs on the `from odata client` form, and rewrites String(36) as unlimited", "cause": "Both rewrite paths rebuilt attributes from the AST, which has no spelling for the OData mapping; the `from odata client` path minted fresh IDs; describe external entity printed GetTypeName() (`String`) instead of formatAttributeType", "file": "mdl/executor/cmd_entities.go (carryStoredAttributeState), cmd_odata.go", "insight": "Carry per attribute by name what the statement cannot spell, in the shared merge, and enumerate every path that rebuilds attributes: there were two statements for one document kind", "refs": ["ako/mxcli#743"]} +{"area": "mdl/executor", "date": "2026-09-27", "symptom": "create or modify odata service over a Studio Pro service: EntitySet PageSize 10000 -> 0, entity sets reordered, member CanBeEmpty recomputed, ExportLevel deleted, AuthenticationTypes marker 1 -> 3", "cause": "The modify path rebuilt entity types/sets from the publish block (no spelling for PageSize without paging, set order, CanBeEmpty); the model had no ExportLevel; the writer used a marker-3 list copied from the legacy writer, not Studio Pro", "file": "mdl/executor/cmd_odata.go (carryPublishedEntityState), mdl/backend/modelsdk/odata_write.go", "insight": "Parity with the legacy writer is not evidence of what Studio Pro writes; measure markers on a Studio Pro fixture. A probe that runs describe output with the verb rewritten to create or modify (mdl/roundtrip TestTestAppCreateOrModifyProbe) shows what a verb switch would lose before switching it", "refs": ["ako/mxcli#743"]} diff --git a/mdl/backend/modelsdk/integration_read.go b/mdl/backend/modelsdk/integration_read.go index a361a432b..0ce146a12 100644 --- a/mdl/backend/modelsdk/integration_read.go +++ b/mdl/backend/modelsdk/integration_read.go @@ -113,6 +113,7 @@ func (b *Backend) ListPublishedODataServices() ([]*model.PublishedODataService, SupportsGraphQL: g.SupportsGraphQL(), UseGeneralization: g.UseGeneralization(), Excluded: g.Excluded(), + ExportLevel: g.ExportLevel(), AuthMicroflow: g.AuthenticationMicroflowQualifiedName(), AuthenticationTypes: append([]string(nil), g.AuthenticationTypesItems()...), AllowedModuleRoles: append([]string(nil), g.AllowedModuleRolesQualifiedNames()...), diff --git a/mdl/backend/modelsdk/odata_read_detail.go b/mdl/backend/modelsdk/odata_read_detail.go index 2136ede82..49df1a97f 100644 --- a/mdl/backend/modelsdk/odata_read_detail.go +++ b/mdl/backend/modelsdk/odata_read_detail.go @@ -157,6 +157,10 @@ func publishedMemberFromRaw(raw map[string]any) *model.PublishedMember { Sortable: jsExtractBool(raw["Sortable"]), IsPartOfKey: jsExtractBool(raw["IsPartOfKey"]), } + if _, ok := raw["CanBeEmpty"]; ok { + v := jsExtractBool(raw["CanBeEmpty"]) + m.CanBeEmpty = &v + } switch m.TypeName { case "ODataPublish$PublishedAttribute": m.Kind = "attribute" diff --git a/mdl/backend/modelsdk/odata_service_carry_test.go b/mdl/backend/modelsdk/odata_service_carry_test.go new file mode 100644 index 000000000..a52481127 --- /dev/null +++ b/mdl/backend/modelsdk/odata_service_carry_test.go @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: Apache-2.0 + +package modelsdkbackend + +import ( + "testing" + + "go.mongodb.org/mongo-driver/v2/bson" + + "github.com/mendixlabs/mxcli/model" + "github.com/mendixlabs/mxcli/modelsdk/codec" +) + +// Running `create or modify odata service` over a Studio Pro-authored service +// (ako/TestApp: MyFirstModule.CarOdataApi, Odata.Published_OData_GraphQL_service, +// Services.OrderODataApi) dropped its ExportLevel and wrote AuthenticationTypes +// with marker 3 where Studio Pro writes 1 on all three (#743). + +func encodePublishedService(t *testing.T, svc *model.PublishedODataService) bson.Raw { + t.Helper() + raw, err := (&codec.Encoder{}).Encode(publishedODataServiceToGen(svc)) + if err != nil { + t.Fatalf("encode: %v", err) + } + return raw +} + +func TestPublishedODataServiceToGen_WritesStoredExportLevel(t *testing.T) { + raw := encodePublishedService(t, &model.PublishedODataService{Name: "CarOdataApi", ExportLevel: "Hidden"}) + v, err := raw.LookupErr("ExportLevel") + if err != nil { + t.Fatal("ExportLevel is absent; a rewrite of a Studio Pro service deletes it") + } + if s, _ := v.StringValueOK(); s != "Hidden" { + t.Errorf("ExportLevel = %v, want Hidden", v) + } + // Control: a service that never had one (created by mxcli) is written as before. + if _, err := encodePublishedService(t, &model.PublishedODataService{Name: "New"}).LookupErr("ExportLevel"); err == nil { + t.Error("an unset ExportLevel was written") + } +} + +func TestPublishedODataServiceToGen_AuthenticationTypesMarkerIsOne(t *testing.T) { + raw := encodePublishedService(t, &model.PublishedODataService{Name: "CarOdataApi", AuthenticationTypes: []string{"Basic"}}) + v, err := raw.LookupErr("AuthenticationTypes") + if err != nil { + t.Fatal("AuthenticationTypes is absent") + } + vals, err := v.Array().Values() + if err != nil || len(vals) != 2 { + t.Fatalf("AuthenticationTypes = %v, want [marker, Basic]", v) + } + if m, ok := vals[0].Int32OK(); !ok || m != 1 { + t.Errorf("marker = %v, want 1 (what Studio Pro writes)", vals[0]) + } +} + +// A member's stored CanBeEmpty is written back as stored; without one the +// writer derives it from the key, as before (#743). +func TestPublishedMemberCanBeEmpty(t *testing.T) { + no, yes := false, true + for _, c := range []struct { + m model.PublishedMember + want bool + }{ + {model.PublishedMember{Kind: "attribute", CanBeEmpty: &no}, false}, + {model.PublishedMember{Kind: "attribute", IsPartOfKey: true, CanBeEmpty: &yes}, true}, + {model.PublishedMember{Kind: "attribute"}, true}, + {model.PublishedMember{Kind: "attribute", IsPartOfKey: true}, false}, + } { + if got := memberCanBeEmpty(&c.m); got != c.want { + t.Errorf("memberCanBeEmpty(%+v) = %v, want %v", c.m, got, c.want) + } + } + if m := publishedMemberFromRaw(map[string]any{"$Type": "ODataPublish$PublishedAttribute", "CanBeEmpty": false}); m.CanBeEmpty == nil || *m.CanBeEmpty { + t.Errorf("stored CanBeEmpty false read as %v", m.CanBeEmpty) + } + if m := publishedMemberFromRaw(map[string]any{"$Type": "ODataPublish$PublishedAttribute"}); m.CanBeEmpty != nil { + t.Errorf("absent CanBeEmpty read as %v", *m.CanBeEmpty) + } +} diff --git a/mdl/backend/modelsdk/odata_write.go b/mdl/backend/modelsdk/odata_write.go index 6c68458b9..3081932ab 100644 --- a/mdl/backend/modelsdk/odata_write.go +++ b/mdl/backend/modelsdk/odata_write.go @@ -10,7 +10,6 @@ import ( "github.com/mendixlabs/mxcli/modelsdk/codec" "github.com/mendixlabs/mxcli/modelsdk/element" mmpr "github.com/mendixlabs/mxcli/modelsdk/mpr" - "github.com/mendixlabs/mxcli/modelsdk/property" ) func init() { @@ -255,8 +254,14 @@ func publishedODataServiceToGen(svc *model.PublishedODataService) element.Elemen // suite (mxcli-formula1 §41). addByNameRefList(g, "AllowedModuleRoles", "", svc.AllowedModuleRoles) if len(svc.AuthenticationTypes) > 0 { - addByNameRefListV3(g, "AuthenticationTypes", svc.AuthenticationTypes) + // Marker 1: what Studio Pro writes on all three published services of + // ako/TestApp. The 3 this used matched the legacy writer, not Studio Pro, + // and churned every rewrite (#743). + addByNameRefList(g, "AuthenticationTypes", "", svc.AuthenticationTypes) } + // Carried when stored, so a rewrite does not delete it; a service mxcli + // creates is written as before (#743). + addStrIf(g, "ExportLevel", svc.ExportLevel) // Pre-assign entity-type IDs so entity sets can point at them by ID. entityTypeIDByName := make(map[string]string, len(svc.EntityTypes)) @@ -419,7 +424,7 @@ func publishedMemberToGen(m *model.PublishedMember, ownerQN string) element.Elem case "association": g := newElem("ODataPublish$PublishedAssociationEnd", memberID) addStr(g, "ExposedName", m.ExposedName) - addBool(g, "CanBeEmpty", !m.IsPartOfKey) + addBool(g, "CanBeEmpty", memberCanBeEmpty(m)) addStr(g, "Description", "") addStr(g, "Summary", "") addStr(g, "Association", qualifyAssociationName(m.Name, ownerQN)) @@ -432,7 +437,7 @@ func publishedMemberToGen(m *model.PublishedMember, ownerQN string) element.Elem case "id": g := newElem("ODataPublish$PublishedId", memberID) addStr(g, "ExposedName", m.ExposedName) - addBool(g, "CanBeEmpty", !m.IsPartOfKey) + addBool(g, "CanBeEmpty", memberCanBeEmpty(m)) addStr(g, "Description", "") addStr(g, "Summary", "") addStr(g, "Attribute", qualifyMemberName(m.Name, ownerQN)) @@ -443,7 +448,7 @@ func publishedMemberToGen(m *model.PublishedMember, ownerQN string) element.Elem default: // attribute g := newElem("ODataPublish$PublishedAttribute", memberID) addStr(g, "ExposedName", m.ExposedName) - addBool(g, "CanBeEmpty", !m.IsPartOfKey) + addBool(g, "CanBeEmpty", memberCanBeEmpty(m)) addStr(g, "Description", "") addStr(g, "Summary", "") addStr(g, "Attribute", qualifyMemberName(m.Name, ownerQN)) @@ -519,16 +524,6 @@ func addStrIf(b *element.Base, name, val string) { } } -// addByNameRefListV3 adds a marker-3 reference-string list (qualified names), -// the form Mendix uses for a published OData service's AuthenticationTypes. -func addByNameRefListV3(b *element.Base, name string, qnames []string) { - p := property.NewByNameRefListV3[element.Element](name, "") - b.AddProperty(p, uint(len(b.Properties()))) - for _, qn := range qnames { - p.Append(qn) - } -} - // boolOrDefault resolves an optional bool: nil means "not specified". func boolOrDefault(v *bool, def bool) bool { if v == nil { @@ -536,3 +531,12 @@ func boolOrDefault(v *bool, def bool) bool { } return *v } + +// memberCanBeEmpty is the stored CanBeEmpty when there is one (#743), else the +// value derived from the key: a key member cannot be empty. +func memberCanBeEmpty(m *model.PublishedMember) bool { + if m.CanBeEmpty != nil { + return *m.CanBeEmpty + } + return !m.IsPartOfKey +} diff --git a/mdl/executor/cmd_odata.go b/mdl/executor/cmd_odata.go index ca2fd4baa..480172496 100644 --- a/mdl/executor/cmd_odata.go +++ b/mdl/executor/cmd_odata.go @@ -331,8 +331,11 @@ func outputPublishedODataServiceMDL(ctx *ExecContext, svc *model.PublishedODataS outputJavadoc(ctx.Output, svc.Description) } - // Plain `create` on purpose; see describeODataClient. - fmt.Fprintf(ctx.Output, "create odata service %s.%s (\n", moduleName, svc.Name) + // `create or modify`: the rewrite carries what this output cannot print + // (ExportLevel, PageSize without paging, entity-set order, CanBeEmpty), and + // TestTestAppRoundTrip holds it to both round-trip laws on the Studio + // Pro-authored services of ako/TestApp (#743). + fmt.Fprintf(ctx.Output, "create or modify odata service %s.%s (\n", moduleName, svc.Name) var props []string if folderPath != "" { @@ -1564,6 +1567,7 @@ func createODataService(ctx *ExecContext, stmt *ast.CreateODataServiceStmt) erro // service — a member removed from the script is removed from // the service, which merging could never express. if len(stmt.Entities) > 0 { + storedTypes, storedSets := svc.EntityTypes, svc.EntitySets svc.EntityTypes = nil svc.EntitySets = nil for _, entityDef := range stmt.Entities { @@ -1571,6 +1575,7 @@ func createODataService(ctx *ExecContext, stmt *ast.CreateODataServiceStmt) erro svc.EntityTypes = append(svc.EntityTypes, entityType) svc.EntitySets = append(svc.EntitySets, entitySet) } + carryPublishedEntityState(storedTypes, storedSets, svc) } // AllowedModuleRoles is granted by a separate statement // (`grant access on odata service …`) and cannot be expressed @@ -1684,6 +1689,53 @@ func createODataService(ctx *ExecContext, stmt *ast.CreateODataServiceStmt) erro return nil } +// carryPublishedEntityState carries onto a service's rebuilt entity types and +// sets what the `publish entity` block has no spelling for, from the stored +// ones (#743): +// - an entity set's PageSize when the statement does not page (describe prints +// PageSize only with UsePaging, and Studio Pro stores 10000 either way); +// - the stored order of the entity sets, which describe prints in entity-type +// order; sets the stored service did not have follow, in statement order; +// - each member's CanBeEmpty, matched by entity and member name. +func carryPublishedEntityState(storedTypes []*model.PublishedEntityType, storedSets []*model.PublishedEntitySet, svc *model.PublishedODataService) { + setIndex := make(map[string]int, len(storedSets)) + setByEntity := make(map[string]*model.PublishedEntitySet, len(storedSets)) + for i, es := range storedSets { + setIndex[es.EntityTypeName] = i + setByEntity[es.EntityTypeName] = es + } + for _, es := range svc.EntitySets { + if old, ok := setByEntity[es.EntityTypeName]; ok && !es.UsePaging && es.PageSize == 0 { + es.PageSize = old.PageSize + } + } + sort.SliceStable(svc.EntitySets, func(i, j int) bool { + a, aok := setIndex[svc.EntitySets[i].EntityTypeName] + b, bok := setIndex[svc.EntitySets[j].EntityTypeName] + switch { + case aok && bok: + return a < b + default: + return aok && !bok + } + }) + + members := map[string]*model.PublishedMember{} // entity + "/" + bare member name + for _, et := range storedTypes { + for _, m := range et.Members { + members[et.Entity+"/"+bareMemberName(m.Name)] = m + } + } + for _, et := range svc.EntityTypes { + for _, m := range et.Members { + if old, ok := members[et.Entity+"/"+bareMemberName(m.Name)]; ok && old.CanBeEmpty != nil { + v := *old.CanBeEmpty + m.CanBeEmpty = &v + } + } + } +} + // alterODataService handles ALTER ODATA SERVICE command. func alterODataService(ctx *ExecContext, stmt *ast.AlterODataServiceStmt) error { diff --git a/mdl/executor/cmd_odata_mock_test.go b/mdl/executor/cmd_odata_mock_test.go index e5e8527ef..d114c9592 100644 --- a/mdl/executor/cmd_odata_mock_test.go +++ b/mdl/executor/cmd_odata_mock_test.go @@ -192,8 +192,8 @@ func TestDescribeODataService_Mock(t *testing.T) { assertNoError(t, describeODataService(ctx, ast.QualifiedName{Module: "MyModule", Name: "CatalogService"})) out := buf.String() - assertContainsStr(t, out, "create odata service") - assertNotContainsStr(t, out, "create or modify odata service") // safe refusal until its carry is proven (ADR-0012) + // The carry is proven by TestTestAppRoundTrip on ako/TestApp's services (#743). + assertContainsStr(t, out, "create or modify odata service") assertContainsStr(t, out, "MyModule.CatalogService") } diff --git a/mdl/executor/cmd_odata_service_carry_test.go b/mdl/executor/cmd_odata_service_carry_test.go new file mode 100644 index 000000000..98cfbcc1e --- /dev/null +++ b/mdl/executor/cmd_odata_service_carry_test.go @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: Apache-2.0 + +package executor + +import ( + "testing" + + "github.com/mendixlabs/mxcli/mdl/ast" + "github.com/mendixlabs/mxcli/model" +) + +// Running a published service's describe output as `create or modify` over the +// Studio Pro-authored ako/TestApp (Services.OrderODataApi and two more) changed +// every entity set's PageSize from 10000 to 0 (describe prints PageSize only +// with UsePaging), reordered the entity sets into entity-type order, and +// recomputed each member's CanBeEmpty (#743). None of the three has a spelling +// in the statement, so the rewrite carries the stored value. +func TestModifyODataService_CarriesPageSizeOrderAndCanBeEmpty(t *testing.T) { + svc, mb, h := existingPublishedService() + no := false + svc.EntityTypes = append(svc.EntityTypes, &model.PublishedEntityType{ + ExposedName: "Line", Entity: "MyModule.Line", + Members: []*model.PublishedMember{{Kind: "attribute", Name: "MyModule.Line.Amount", ExposedName: "Amount", CanBeEmpty: &no}}, + }) + svc.EntityTypes[0].Members[0].CanBeEmpty = &no + // Stored set order is Lines, Orders: not the entity-type order. + svc.EntitySets = []*model.PublishedEntitySet{ + {ExposedName: "Lines", EntityTypeName: "MyModule.Line", PageSize: 10000}, + {ExposedName: "Orders", EntityTypeName: "MyModule.Order", PageSize: 10000}, + } + var updated *model.PublishedODataService + mb.UpdatePublishedODataServiceFunc = func(s *model.PublishedODataService) error { updated = s; return nil } + ctx, _ := newMockCtx(t, withBackend(mb), withHierarchy(h)) + + stmt := &ast.CreateODataServiceStmt{ + Name: ast.QualifiedName{Module: "MyModule", Name: "CatalogService"}, + CreateOrModify: true, + Entities: []*ast.PublishedEntityDef{ + {Entity: ast.QualifiedName{Module: "MyModule", Name: "Order"}, ExposedName: "Orders", + Members: []*ast.PublishedMemberDef{{Name: "Label", ExposedName: "label"}}}, + {Entity: ast.QualifiedName{Module: "MyModule", Name: "Line"}, ExposedName: "Lines", + Members: []*ast.PublishedMemberDef{{Name: "Amount", ExposedName: "Amount"}, {Name: "Added", ExposedName: "Added"}}}, + {Entity: ast.QualifiedName{Module: "MyModule", Name: "New"}, ExposedName: "News", UsePaging: true, PageSize: 50}, + }, + } + assertNoError(t, createODataService(ctx, stmt)) + if updated == nil { + t.Fatal("the service was never updated") + } + + var order []string + for _, es := range updated.EntitySets { + order = append(order, es.ExposedName) + } + if len(order) != 3 || order[0] != "Lines" || order[1] != "Orders" || order[2] != "News" { + t.Errorf("entity set order = %v, want the stored [Lines Orders] then the new News", order) + } + for _, es := range updated.EntitySets { + want := 10000 + if es.ExposedName == "News" { + want = 50 // declared: the statement wins + } + if es.PageSize != want { + t.Errorf("%s PageSize = %d, want %d", es.ExposedName, es.PageSize, want) + } + } + if m := findPublishedMember(t, updated, "Label"); m.CanBeEmpty == nil || *m.CanBeEmpty { + t.Errorf("Label CanBeEmpty = %v, want the stored false", m.CanBeEmpty) + } + if m := findPublishedMember(t, updated, "Amount"); m.CanBeEmpty == nil || *m.CanBeEmpty { + t.Errorf("Amount CanBeEmpty = %v, want the stored false", m.CanBeEmpty) + } + // Control: a member the stored service did not publish carries nothing. + if m := findPublishedMember(t, updated, "Added"); m.CanBeEmpty != nil { + t.Errorf("new member Added got CanBeEmpty %v", *m.CanBeEmpty) + } +} diff --git a/model/types.go b/model/types.go index 6e7d30868..351913cca 100644 --- a/model/types.go +++ b/model/types.go @@ -525,6 +525,9 @@ type PublishedODataService struct { Microflows []*PublishedMicroflow `json:"microflows,omitempty"` AllowedModuleRoles []string `json:"allowedModuleRoles,omitempty"` Excluded bool `json:"excluded,omitempty"` + // ExportLevel has no MDL spelling; it is carried from what is stored so a + // rewrite does not delete it (#743). Empty on a service mxcli creates. + ExportLevel string `json:"exportLevel,omitempty"` } // PublishedMicroflow is a microflow exposed as an OData action. @@ -606,6 +609,11 @@ type PublishedMember struct { Sortable bool `json:"sortable,omitempty"` IsPartOfKey bool `json:"isPartOfKey,omitempty"` + // CanBeEmpty is the stored value, carried by a rewrite since MDL has no + // spelling for it (#743). nil means not stored: the writer derives it as + // !IsPartOfKey, as it always did. + CanBeEmpty *bool `json:"canBeEmpty,omitempty"` + // EdmType is the OData EDM type the attribute is published as (e.g. // "Edm.String"). Studio Pro stores this on every ODataPublish$PublishedAttribute; // without it `mx check` reports CE5016 ("published as ."). Attribute members only. From d5ce2d903bf170260c18dc5e4dec86a4863845be Mon Sep 17 00:00:00 2001 From: Ako Date: Sun, 27 Sep 2026 14:40:02 +0000 Subject: [PATCH 05/13] fix(refusal): point workflow and OData client to alter, not create or modify (#743) A plain `create` of an existing workflow or OData client is refused, and the refusal said "use create or modify". For these two types that is the rewrite that still loses Studio Pro-authored content (event sub-processes and outcome flows; UseQuerySegment, catalog, proxy and microflow settings, icon). The message now points to `alter workflow` / `alter odata client` and says why the whole-document rewrite is not yet safe. Co-Authored-By: Claude Opus 5.5 --- mdl/executor/cmd_odata.go | 8 ++- mdl/executor/cmd_workflows_write.go | 6 ++- mdl/executor/refusal_advice_743_test.go | 70 +++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 mdl/executor/refusal_advice_743_test.go diff --git a/mdl/executor/cmd_odata.go b/mdl/executor/cmd_odata.go index 480172496..ccd0fc245 100644 --- a/mdl/executor/cmd_odata.go +++ b/mdl/executor/cmd_odata.go @@ -1132,7 +1132,13 @@ func createODataClient(ctx *ExecContext, stmt *ast.CreateODataClientStmt) error } return nil } - return mdlerrors.NewAlreadyExistsMsg("OData client", modName+"."+svc.Name, fmt.Sprintf("OData client already exists: %s.%s (use create or modify to update)", modName, svc.Name)) + // Not "use create or modify": that rewrite does not yet carry what + // describe cannot print and would lose Studio Pro-authored + // settings (#743). + return mdlerrors.NewAlreadyExistsMsg("OData client", modName+"."+svc.Name, fmt.Sprintf( + "OData client already exists: %s.%s — use 'alter odata client %s.%s set ...' to change it; "+ + "'create or modify odata client' rewrites the whole client and does not yet keep everything Studio Pro stores "+ + "(UseQuerySegment, catalog, proxy and microflow settings, icon)", modName, svc.Name, modName, svc.Name)) } } } diff --git a/mdl/executor/cmd_workflows_write.go b/mdl/executor/cmd_workflows_write.go index 2dd6b76f3..0a4d97f92 100644 --- a/mdl/executor/cmd_workflows_write.go +++ b/mdl/executor/cmd_workflows_write.go @@ -127,7 +127,11 @@ func execCreateWorkflow(ctx *ExecContext, s *ast.CreateWorkflowStmt) error { func(w *workflows.Workflow) bool { return w.Excluded }, ); ok { if !s.CreateOrModify { - return mdlerrors.NewAlreadyExistsMsg("workflow", s.Name.Module+"."+s.Name.Name, "workflow '"+s.Name.Module+"."+s.Name.Name+"' already exists (use create or modify to overwrite)") + // Not "use create or modify": that rewrite does not yet carry what + // describe cannot print (event sub-processes, outcome flows, activity + // names) and would lose Studio Pro-authored content (#743). + return mdlerrors.NewAlreadyExistsMsg("workflow", s.Name.Module+"."+s.Name.Name, "workflow '"+s.Name.Module+"."+s.Name.Name+"' already exists — use 'alter workflow "+s.Name.Module+"."+s.Name.Name+" ...' to change it; "+ + "'create or modify workflow' rewrites the whole workflow and does not yet keep everything Studio Pro stores (event sub-processes, outcome flows)") } existingID = existing.ID existingExcluded = existing.Excluded diff --git a/mdl/executor/refusal_advice_743_test.go b/mdl/executor/refusal_advice_743_test.go new file mode 100644 index 000000000..7cac9b068 --- /dev/null +++ b/mdl/executor/refusal_advice_743_test.go @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: Apache-2.0 + +package executor + +import ( + "strings" + "testing" + + "github.com/mendixlabs/mxcli/mdl/ast" + "github.com/mendixlabs/mxcli/mdl/backend/mock" + "github.com/mendixlabs/mxcli/model" + "github.com/mendixlabs/mxcli/sdk/workflows" +) + +// A plain `create` of an existing workflow or OData client is refused, and the +// refusal used to say "use create or modify". For these two types that is the +// rewrite that loses Studio Pro-authored content (#743: event sub-processes and +// outcome flows of a workflow; UseQuerySegment, the catalog, proxy and microflow +// settings and the icon of an OData client). Until the carry lands the advice +// points to `alter` and says why. + +func assertSafeAdvice(t *testing.T, err error, alter string) { + t.Helper() + if err == nil { + t.Fatal("a plain create of an existing document was not refused") + } + msg := err.Error() + if !strings.Contains(msg, "already exists") { + t.Fatalf("unexpected error: %v", err) + } + if !strings.Contains(msg, alter) { + t.Errorf("the refusal does not point to %q: %s", alter, msg) + } + if strings.Contains(msg, "use create or modify to") { + t.Errorf("the refusal still recommends the lossy rewrite: %s", msg) + } +} + +func TestCreateODataClient_ExistsAdvisesAlter(t *testing.T) { + mod := mkModule("MyModule") + existing := &model.ConsumedODataService{BaseElement: model.BaseElement{ID: nextID("cos")}, ContainerID: mod.ID, Name: "Api"} + h := mkHierarchy(mod) + withContainer(h, existing.ContainerID, mod.ID) + mb := &mock.MockBackend{ + IsConnectedFunc: func() bool { return true }, + ListModulesFunc: func() ([]*model.Module, error) { return []*model.Module{mod}, nil }, + ListConstantsFunc: func() ([]*model.Constant, error) { return nil, nil }, + ListConsumedODataServicesFunc: func() ([]*model.ConsumedODataService, error) { + return []*model.ConsumedODataService{existing}, nil + }, + } + ctx, _ := newMockCtx(t, withBackend(mb), withHierarchy(h)) + prog := parseMDL(t, "create odata client MyModule.Api (\n ODataVersion: OData4,\n MetadataUrl: 'https://example.com/odata/$metadata'\n);") + assertSafeAdvice(t, createODataClient(ctx, prog.Statements[0].(*ast.CreateODataClientStmt)), "alter odata client") +} + +func TestCreateWorkflow_ExistsAdvisesAlter(t *testing.T) { + mod := mkModule("MyModule") + existing := &workflows.Workflow{BaseElement: model.BaseElement{ID: nextID("wf")}, ContainerID: mod.ID, Name: "Approve"} + h := mkHierarchy(mod) + withContainer(h, existing.ContainerID, mod.ID) + mb := &mock.MockBackend{ + IsConnectedFunc: func() bool { return true }, + ListModulesFunc: func() ([]*model.Module, error) { return []*model.Module{mod}, nil }, + ListWorkflowsFunc: func() ([]*workflows.Workflow, error) { return []*workflows.Workflow{existing}, nil }, + } + ctx, _ := newMockCtx(t, withBackend(mb), withHierarchy(h)) + prog := parseMDL(t, "create workflow MyModule.Approve\nbegin\nend workflow;") + assertSafeAdvice(t, execCreateWorkflow(ctx, prog.Statements[0].(*ast.CreateWorkflowStmt)), "alter workflow") +} From 1580d2538f8d82a023e34e696c61859402b02367 Mon Sep 17 00:00:00 2001 From: Ako Date: Sun, 27 Sep 2026 14:40:04 +0000 Subject: [PATCH 06/13] test(roundtrip): add ako/TestApp as a submodule fixture, with a create-or-modify probe (#743) PedApp has no workflow, OData client or service, or external entity, so the harness could not see what a rewrite of them loses. ako/TestApp, Studio Pro-authored, is now pinned as the submodule testdata/testapp (11a8fca) and round-tripped by TestTestAppRoundTrip with its own allowlist (may only shrink). The tests skip, saying how to initialise it, when the submodule is absent; CI checks it out (submodules: true, build-and-test only). - the harness takes a fixture (dir, .mpr, allowlist); PedApp is unchanged; - unitKeywords maps Rest$ConsumedODataService (odata client) and ODataPublish$PublishedODataService2 (odata service); external entities are also enumerated as `external entity` (workflows were already mapped); - TestTestAppCreateOrModifyProbe runs the describe output of each kind that still prints a plain `create` (workflow, odata client, external entity) with the verb rewritten to `create or modify`, under the same laws and its own allowlist. A kind switches its describe verb once none of its documents is listed there; odata service switched on that evidence. Measured at introduction: 142 of 775 TestApp documents keep both laws; the rest are the #721 classes on a larger fixture, or the three deferred kinds. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/push-test.yml | 4 + .gitmodules | 3 + mdl/roundtrip/doc.go | 7 +- mdl/roundtrip/pedapp_roundtrip_test.go | 167 ++++- mdl/roundtrip/testapp_allowlist_test.go | 662 ++++++++++++++++++ .../testapp_create_or_modify_test.go | 94 +++ testdata/testapp | 1 + 7 files changed, 900 insertions(+), 38 deletions(-) create mode 100644 .gitmodules create mode 100644 mdl/roundtrip/testapp_allowlist_test.go create mode 100644 mdl/roundtrip/testapp_create_or_modify_test.go create mode 160000 testdata/testapp diff --git a/.github/workflows/push-test.yml b/.github/workflows/push-test.yml index 262c5d23f..5efb0878d 100644 --- a/.github/workflows/push-test.yml +++ b/.github/workflows/push-test.yml @@ -116,6 +116,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 + with: + # testdata/testapp (ako/TestApp) is the round-trip harness's second + # Studio Pro-authored fixture (#743); without it that test skips. + submodules: true - uses: actions/setup-go@v7 with: go-version: '1.26.6' diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..529f38c10 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "testdata/testapp"] + path = testdata/testapp + url = https://github.com/ako/TestApp.git diff --git a/mdl/roundtrip/doc.go b/mdl/roundtrip/doc.go index bc1abc523..2fc720c31 100644 --- a/mdl/roundtrip/doc.go +++ b/mdl/roundtrip/doc.go @@ -1,7 +1,10 @@ // SPDX-License-Identifier: Apache-2.0 -// Package roundtrip holds the round-trip harness over the committed Studio -// Pro-authored fixture (testdata/pedapp). It has no non-test code: the harness +// Package roundtrip holds the round-trip harness over the Studio Pro-authored +// fixtures: PedApp (testdata/pedapp, committed) and ako/TestApp +// (testdata/testapp, a git submodule with workflows, OData clients and services +// and external entities; its tests skip when the submodule is not initialised). +// Each fixture has its own allowlist. It has no non-test code: the harness // is an integration test (`-tags integration`) that enforces the two // round-trip laws of ADR-0012 on every document the fixture contains. // diff --git a/mdl/roundtrip/pedapp_roundtrip_test.go b/mdl/roundtrip/pedapp_roundtrip_test.go index 098295a37..13a5e0c67 100644 --- a/mdl/roundtrip/pedapp_roundtrip_test.go +++ b/mdl/roundtrip/pedapp_roundtrip_test.go @@ -24,13 +24,43 @@ import ( mmpr "github.com/mendixlabs/mxcli/modelsdk/mpr" ) -// fixtureDir is PedApp (Mendix 11.13), authored in Studio Pro from marketplace +// fixture is one Studio Pro-authored project the harness round-trips, with its +// own allowlist. Each allowlist may only shrink. +type fixture struct { + name string // for messages + dir string // the project directory, relative to this package + mpr string // the .mpr file name inside dir + // minDocs is the fewest documents the enumeration may find; far fewer means + // the enumeration broke, and a harness that looks at nothing passes. + minDocs int + knownFailures map[string]knownFailure + // optional fixtures (a git submodule) skip with this message when absent + // instead of failing. + skipIfMissing string +} + +// pedApp is PedApp (Mendix 11.13), authored in Studio Pro from marketplace // modules. See testdata/pedapp/README.md for what it contains and why it must -// stay pristine. -const ( - fixtureDir = "../../testdata/pedapp" - fixtureMPR = "PedApp.mpr" -) +// stay pristine. It is committed, so it is never skipped. +var pedApp = fixture{ + name: "PedApp", + dir: "../../testdata/pedapp", + mpr: "PedApp.mpr", + minDocs: 100, + knownFailures: knownFailures, +} + +// testApp is ako/TestApp, a Studio Pro-authored project pinned as the git +// submodule testdata/testapp. It has what PedApp lacks: workflows, OData +// clients and services, and external entities (#743). +var testApp = fixture{ + name: "TestApp", + dir: "../../testdata/testapp/TestApp", + mpr: "TestApp.mpr", + minDocs: 100, + knownFailures: testAppKnownFailures, + skipIfMissing: "the TestApp fixture is a git submodule that is not initialised; run `git submodule update --init testdata/testapp` to round-trip it", +} // law names one way a document can fail the round trip. A document's outcome is // the set of laws it breaks; an empty set is a pass. @@ -65,15 +95,19 @@ type knownFailure struct { // The test // --------------------------------------------------------------------------- -func TestPedAppRoundTrip(t *testing.T) { - h := newHarness(t) +func TestPedAppRoundTrip(t *testing.T) { runRoundTrip(t, pedApp) } + +// TestTestAppRoundTrip round-trips ako/TestApp (the testdata/testapp +// submodule). It skips, saying so, when the submodule is not initialised. +func TestTestAppRoundTrip(t *testing.T) { runRoundTrip(t, testApp) } + +func runRoundTrip(t *testing.T, fx fixture) { + h := newFixtureHarness(t, fx) defer h.close() docs := h.documents() - if len(docs) < 100 { - // The fixture has ~200 describable documents; far fewer means the - // enumeration broke, and a harness that looks at nothing passes. - t.Fatalf("enumerated only %d documents from the fixture — the enumeration is broken", len(docs)) + if len(docs) < fx.minDocs { + t.Fatalf("enumerated only %d documents from %s — the enumeration is broken", len(docs), fx.name) } seen := map[string]bool{} @@ -87,7 +121,7 @@ func TestPedAppRoundTrip(t *testing.T) { if len(got.broken) == 0 { passed++ } - judge(t, key, got) + judge(t, fx.knownFailures, key, got) }) } @@ -98,9 +132,9 @@ func TestPedAppRoundTrip(t *testing.T) { } t.Logf("%d of %d documents round-trip", passed, ran) - for key := range knownFailures { + for key := range fx.knownFailures { if !seen[key] { - t.Errorf("knownFailures lists %q, which the fixture does not contain — stale entry, remove it", key) + t.Errorf("the %s allowlist lists %q, which the fixture does not contain — stale entry, remove it", fx.name, key) } } } @@ -182,9 +216,9 @@ func TestPedAppRoundTrip_MoveIsWritten(t *testing.T) { } // judge compares one document's outcome with the allowlist. -func judge(t *testing.T, key string, got outcome) { +func judge(t *testing.T, allow map[string]knownFailure, key string, got outcome) { t.Helper() - want, listed := knownFailures[key] + want, listed := allow[key] wantSet := map[law]bool{} for _, l := range want.laws { wantSet[l] = true @@ -222,7 +256,7 @@ func judge(t *testing.T, key string, got outcome) { if got.refused != "" { t.Logf("refused, nothing written: %s", got.refused) } - t.Logf("outcome %v", got.broken) + t.Logf("outcome %s %v", key, got.broken) } // --------------------------------------------------------------------------- @@ -231,6 +265,7 @@ func judge(t *testing.T, key string, got outcome) { type harness struct { t *testing.T + fx fixture fixture map[string][]byte // the committed fixture, by path relative to its root dir string // the working copy mpr string @@ -264,20 +299,26 @@ func isRefusal(err error) bool { return false } -func newHarness(t *testing.T) *harness { +// newHarness is a harness on PedApp, the committed fixture. +func newHarness(t *testing.T) *harness { return newFixtureHarness(t, pedApp) } + +func newFixtureHarness(t *testing.T, fx fixture) *harness { t.Helper() - src, err := filepath.Abs(fixtureDir) + src, err := filepath.Abs(fx.dir) if err != nil { t.Fatal(err) } - if _, err := os.Stat(filepath.Join(src, fixtureMPR)); err != nil { + if _, err := os.Stat(filepath.Join(src, fx.mpr)); err != nil { + if fx.skipIfMissing != "" { + t.Skipf("%s: %s (%v)", fx.name, fx.skipIfMissing, err) + } t.Fatalf("fixture missing: %v", err) } - h := &harness{t: t, dir: t.TempDir(), fixture: readFixture(t, src)} - h.mpr = filepath.Join(h.dir, fixtureMPR) - // Widget packages are stripped to their XML definitions (see the fixture - // README); they are all a page build needs, and are copied once since no - // round trip writes them. + h := &harness{t: t, fx: fx, dir: t.TempDir(), fixture: readFixture(t, src, fx.mpr)} + h.mpr = filepath.Join(h.dir, fx.mpr) + // Widget packages (in PedApp stripped to their XML definitions, see its + // README) are all a page build needs, and are copied once since no round + // trip writes them. if err := copyDir(filepath.Join(src, "widgets"), filepath.Join(h.dir, "widgets")); err != nil { t.Fatalf("copy widgets: %v", err) } @@ -289,7 +330,7 @@ func newHarness(t *testing.T) *harness { // Precondition: connecting must not itself write, or every comparison // below would be against a copy that is no longer the fixture. for rel, want := range h.fixture { - if rel == fixtureMPR { + if rel == fx.mpr { continue // SQLite metadata; units are compared through the reader } if got, err := os.ReadFile(filepath.Join(h.dir, rel)); err != nil || !bytes.Equal(got, want) { @@ -352,7 +393,12 @@ func (h *harness) exec(script string) error { // roundTrip runs describe -> exec -> describe for one document and reports the // laws it breaks. The working copy is restored afterwards if anything was // written. -func (h *harness) roundTrip(d document) outcome { +func (h *harness) roundTrip(d document) outcome { return h.roundTripWith(d, nil) } + +// roundTripWith is roundTrip with the describe output passed through rewrite +// before it is executed; PutGet still compares against the unrewritten first +// describe. A nil rewrite executes the output unchanged. +func (h *harness) roundTripWith(d document, rewrite func(string) string) outcome { var o outcome fail := func(l law, format string, args ...any) { o.broken = append(o.broken, l) @@ -365,9 +411,13 @@ func (h *harness) roundTrip(d document) outcome { return o } - prog, errs := visitor.Build(first) + script := first + if rewrite != nil { + script = rewrite(first) + } + prog, errs := visitor.Build(script) if len(errs) > 0 { - fail(lawParse, "%v\n--- describe output ---\n%s", errs[0], first) + fail(lawParse, "%v\n--- executed script ---\n%s", errs[0], script) return o } if len(prog.Statements) == 0 { @@ -385,12 +435,12 @@ func (h *harness) roundTrip(d document) outcome { // A refusal that wrote nothing keeps both laws. o.refused = execErr.Error() default: - fail(lawExec, "%v\n--- describe output ---\n%s", execErr, first) + fail(lawExec, "%v\n--- executed script ---\n%s", execErr, script) } if len(changed) > 0 { - fail(lawGetPut, "executing the unchanged describe output wrote %d unit(s):\n %s\n--- describe output ---\n%s", - len(changed), strings.Join(changed, "\n "), first) + fail(lawGetPut, "executing the describe output wrote %d unit(s):\n %s\n--- executed script ---\n%s", + len(changed), strings.Join(changed, "\n "), script) } // PutGet. With no write this also catches a describe that is not @@ -456,7 +506,7 @@ func (h *harness) snapshot() snapshot { rel, _ := filepath.Rel(h.dir, p) top := strings.SplitN(rel, string(filepath.Separator), 2)[0] switch { - case top == "mprcontents" || top == "widgets" || top == ".mxcli" || strings.HasPrefix(top, fixtureMPR): + case top == "mprcontents" || top == "widgets" || top == ".mxcli" || strings.HasPrefix(top, h.fx.mpr): if info.IsDir() { return filepath.SkipDir } @@ -549,6 +599,8 @@ var unitKeywords = map[string]string{ "JavaActions$JavaAction": "java action", "JavaScriptActions$JavaScriptAction": "javascript action", "Workflows$Workflow": "workflow", + "Rest$ConsumedODataService": "odata client", + "ODataPublish$PublishedODataService2": "odata service", "Menus$MenuDocument": "menu", "Images$ImageCollection": "image collection", "JsonStructures$JsonStructure": "json structure", @@ -615,6 +667,11 @@ func (h *harness) documents() []document { for _, n := range childNames(doc, "Entities") { docs = append(docs, document{"entity", mod + "." + n}) } + // An external entity is also described on its own, by `describe + // external entity`, which prints the `from odata client` form. + for _, n := range externalEntityNames(doc) { + docs = append(docs, document{"external entity", mod + "." + n}) + } for _, n := range childNames(doc, "Associations") { docs = append(docs, document{"association", mod + "." + n}) } @@ -665,6 +722,44 @@ func typeAndName(b []byte) (string, string) { return typ, name } +// externalEntityNames returns the Name of every entity in a domain model whose +// Source is an OData remote entity source. +func externalEntityNames(doc bson.D) []string { + var out []string + for _, e := range doc { + if e.Key != "Entities" { + continue + } + arr, _ := e.Value.(bson.A) + for _, item := range arr { + ent, ok := item.(bson.D) + if !ok { + continue + } + var name string + external := false + for _, f := range ent { + switch f.Key { + case "Name": + name, _ = f.Value.(string) + case "Source": + if src, ok := f.Value.(bson.D); ok { + for _, sf := range src { + if sf.Key == "$Type" && sf.Value == "Rest$ODataRemoteEntitySource" { + external = true + } + } + } + } + } + if external && name != "" { + out = append(out, name) + } + } + } + return out +} + // childNames returns the Name of every element in a BSON array property. Mendix // arrays carry a leading type-marker integer, which is skipped. func childNames(doc bson.D, prop string) []string { @@ -729,7 +824,7 @@ func lineDiff(a, b string) string { // readFixture loads the .mpr and mprcontents/ into memory once, so restoring // the working copy never reads the (possibly slow) checkout again. -func readFixture(t *testing.T, src string) map[string][]byte { +func readFixture(t *testing.T, src, mprName string) map[string][]byte { t.Helper() out := map[string][]byte{} err := filepath.Walk(src, func(p string, info os.FileInfo, err error) error { @@ -737,7 +832,7 @@ func readFixture(t *testing.T, src string) map[string][]byte { return err } rel, _ := filepath.Rel(src, p) - if rel != fixtureMPR && !strings.HasPrefix(rel, "mprcontents"+string(filepath.Separator)) { + if rel != mprName && !strings.HasPrefix(rel, "mprcontents"+string(filepath.Separator)) { return nil } b, err := os.ReadFile(p) diff --git a/mdl/roundtrip/testapp_allowlist_test.go b/mdl/roundtrip/testapp_allowlist_test.go new file mode 100644 index 000000000..ad3778331 --- /dev/null +++ b/mdl/roundtrip/testapp_allowlist_test.go @@ -0,0 +1,662 @@ +// SPDX-License-Identifier: Apache-2.0 + +//go:build integration + +package roundtrip + +// testAppKnownFailures is the allowlist for ako/TestApp (testdata/testapp), kept +// apart from PedApp's so each fixture's list can only shrink on its own. The +// rules are those of knownFailures in allowlist_test.go. +// +// Measured on 2026-09-27 at TestApp 11a8fca, when TestApp joined the harness +// (#743): 142 of 775 documents keep both laws. The #743 entries are the three +// kinds whose describe still prints a plain `create`; their `create or modify` +// rewrites are measured by TestTestAppCreateOrModifyProbe. Everything else is +// the #721 classes on a larger fixture and has not been triaged per document. +var testAppKnownFailures = map[string]knownFailure{ + "association Administration.AccountPasswordData_Account": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association Clients.Customer_Order": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association Clients.OrderLine_Order": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association Clients.Order_GetCustomerOrdersResponse": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association Clients.Order_SaveOrder": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association Clients.Product_OrderLine": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association Mappings.OrderLine_Order": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association Mappings.OrderLine_Product": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association Mappings.Order_Customer": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association Rules.BusinessRule_RuleCategory": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association Rules.RuleAction_BusinessRule": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association Rules.RuleExecutionLog_BusinessRule": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association ViewAssociations.persistent_order": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.CleanupHelper_WorkflowDefinition": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.ConflictReasonGroup_Workflow": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.ConflictReasonGroup_WorkflowDefinition": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.ConflictedWorkflowDefinitionView_WorkflowDefinition": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.ConflictedWorkflowHelper_Workflow": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.ConflictedWorkflowView_ConflictReasonGroup": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.ConflictedWorkflowView_CurrentActivitiesGroup": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.ConflictedWorkflowView_ExecutionPathGroup": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.ConflictedWorkflowView_Workflow": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.ConflictedWorkflowView_WorkflowDefinition": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.CurrentActivitiesGroup_Workflow": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.CurrentActivitiesGroup_WorkflowDefinition": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.DashboardContext_DefinitionHelperTask": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.DashboardContext_DefinitionHelperWorkflow": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.DashboardContext_Session": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.DashboardContext_TaskSummary": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.DashboardContext_WorkflowDefinition": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.DashboardContext_WorkflowSummary": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.DashboardContext_WorkflowTaskDefinition": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.DefinitionHelper_DashboardContext": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.DefinitionHelper_DefinitionHelperParent": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.ExecutionPathGroup_Workflow": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.ExecutionPathGroup_WorkflowDefinition": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.MyInitiatedWorkflowView_Initiator": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.MyInitiatedWorkflowView_ParentWorkflow": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.MyInitiatedWorkflowView_Workflow": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.TaskAssignmentHelper_User": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.TaskAssignmentHelper_WorkflowUserTask": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.TaskSeries_DashboardContext": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.TimelineViewer_Workflow": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.UserTaskOutcomeView_User": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.UserTaskOutcomeView_UserTaskView": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.UserTaskOutcomeView_WorkflowUserTaskOutcome": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.UserTaskView_Assignees": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.UserTaskView_TargetUsers": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.UserTaskView_WorkflowEndedUserTask": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.UserTaskView_WorkflowUserTask": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.UserTaskView_WorkflowUserTaskDefinition": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.UserTaskView_WorkflowView": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowAttachment_WorkflowComment": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowAuditTrailRecord_Workflow": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowAuditTrailRecord_WorkflowDefinition": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowCommentHelper_WorkflowComment": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowComment_Workflow": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowDefinitionHelper_WorkflowDefinition": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowGroupHelper_WorkflowGroup": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowGroupView_WorkflowGroup": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowSeries_DashboardContext": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowSummary_WorkflowDefinition": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowTaskDetail_DashboardContext": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowUserTaskView_Workflow": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowUserTaskView_WorkflowEndedUserTask": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowUserTaskView_WorkflowSubProcess": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowUserTaskView_WorkflowUserTask": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowUserTaskView_WorkflowUserTaskDefinition": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowView_Initiator": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowView_Workflow": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowView_WorkflowDefinition": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Alert": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.AlertIcon": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.AlertIcon_WithAction": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Alert_WithAction": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Breadcrumb": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Breadcrumb_Underline": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Card": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Card_Action": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Card_ActionWithImage": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Card_Background": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Card_WithImage": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Form_Horizontal": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Form_Horizontal_WithAction": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Form_Horizontal_WithTitle": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Form_Vertical": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Form_Vertical_WithAction": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Form_Vertical_WithTitle": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Heroheader": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Heroheader_Background": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Heroheader_WithAction": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.ListItem_DoubleLine": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.ListItem_SingleLine": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.ListItem_WithImage": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.List_Cards": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.List_WithImage": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Master_Detail": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Pageheader": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.PageheaderImage": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.PageheaderImage_WithBack": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.PageheaderImage_WithControls": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Pageheader_WithBack": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Pageheader_WithControls": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Pageheader_WithSearch": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Timeline": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Timeline_WithImage": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Wizard_Arrow": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Wizard_Arrow_Step": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Wizard_Circle": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Wizard_Circle_Step": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block FeedbackModule.FeedbackWidget": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Administration.Account": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Administration.AccountPasswordData": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Atlas_Web_Content.LoginContext": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Clients.Customer": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Clients.GetCustomerOrdersResponse": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Clients.Order": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Clients.OrderLine": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Clients.Orders": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Clients.Product": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Clients.Root": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Clients.SaveOrder": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity FeedbackModule.Feedback": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity FeedbackModule.ResponseHelper": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Mappings.Customer": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Mappings.Item": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Mappings.Order": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Mappings.OrderLine": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Mappings.Product": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity MyFirstModule.Car": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity MyFirstModule.VCar": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity NanoflowCommons.Geolocation": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity NanoflowCommons.Position": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Odata.Devices": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Pages.Vehicle": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Rules.BusinessRule": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Rules.RuleAction": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Rules.RuleCategory": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Rules.RuleExecutionLog": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity ViewAssociations.OrdersVE": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.AssignmentHelper": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.AuditTrailViewer": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.CleanupHelper": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.Configuration": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.ConflictReasonGroup": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.ConflictedWorkflowDefinitionView": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "entity: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.ConflictedWorkflowHelper": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.ConflictedWorkflowView": {laws: []law{lawExec}, issue: "#721", why: "entity: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.CurrentActivitiesGroup": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.DashboardContext": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.DefinitionHelper": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.DurationHelper": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.ExecutionPathGroup": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.MyInitiatedWorkflowView": {laws: []law{lawExec}, issue: "#721", why: "entity: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.NotificationArea": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.TaskAssignmentHelper": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.TaskCount": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.TaskSeries": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.TaskSummary": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.TimelineViewer": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.UserTaskOutcomeView": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.UserTaskTimeLine": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.UserTaskView": {laws: []law{lawExec}, issue: "#721", why: "entity: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.WorkflowAttachment": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "entity: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.WorkflowAuditTrailRecord": {laws: []law{lawExec}, issue: "#721", why: "entity: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.WorkflowComment": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "entity: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.WorkflowCommentHelper": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.WorkflowDefinitionHelper": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.WorkflowGroupHelper": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.WorkflowGroupView": {laws: []law{lawParse}, issue: "#721", why: "entity: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.WorkflowSeries": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.WorkflowSummary": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.WorkflowTaskDetail": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.WorkflowUserTaskView": {laws: []law{lawExec}, issue: "#721", why: "entity: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.WorkflowView": {laws: []law{lawExec}, issue: "#721", why: "entity: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity workflow.workfow1context": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "enumeration WorkflowCommons.Enum_NotificationArea_RenderAs": {laws: []law{lawGetPut}, issue: "#721", why: "enumeration: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "export mapping Clients.SoapOrderExportMapping": {laws: []law{lawGetPut}, issue: "#721", why: "export mapping: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "export mapping Services.OrdersExportMapping": {laws: []law{lawGetPut}, issue: "#721", why: "export mapping: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "external entity Clients.Orders": {laws: []law{lawExec}, issue: "#743", why: "describe external entity prints a plain create, refused on the existing entity; its create or modify probe leaves only #721 B"}, + "external entity Odata.Devices": {laws: []law{lawExec}, issue: "#743", why: "describe external entity prints a plain create, refused on the existing entity; its create or modify probe leaves only #721 B"}, + "import mapping Clients.SoapCustomerOrdersImportMapping": {laws: []law{lawGetPut}, issue: "#721", why: "import mapping: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "import mapping Clients.SoapOrdersImportMapping": {laws: []law{lawGetPut}, issue: "#721", why: "import mapping: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action DataWidgets.Reset_All_Filters": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action DataWidgets.Reset_Filter": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action DataWidgets.Set_Filter": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action FeedbackModule.JS_GetFeedbackStorageObject": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.DraftEmail": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.FindObjectWithGUID": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.Geocode": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.GetCurrentLocation": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.GetCurrentLocationMinimumAccuracy": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.GetGuid": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.GetObjectByGuid": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.GetStorageItemObject": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.GetStorageItemObjectList": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.RefreshEntity": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.RefreshObject": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.ReverseGeocode": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.SetStorageItemObject": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.SetStorageItemObjectList": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.SetStorageItemString": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.Share": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.ShowConfirmation": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.ShowProgress": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.SignIn": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action WebActions.TakePicture": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "menu Atlas_Core.Phone_Menu": {laws: []law{lawGetPut}, issue: "#721", why: "menu: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "menu Atlas_Core.Tablet_Menu": {laws: []law{lawGetPut}, issue: "#721", why: "menu: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow Administration.ChangeMyPassword": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow Administration.ChangePassword": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow Administration.ManageMyAccount": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow Administration.NewAccount": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow Administration.NewWebServiceAccount": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow Administration.SaveNewAccount": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow Administration.ShowMyPasswordForm": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow Administration.ShowPasswordForm": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow Clients.GetCustomerOrders": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow Clients.GetOdataCustomerOrders": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow Clients.GetOdataOrders": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow Clients.GetOrders": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow Clients.GetProductId": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow Clients.GetRestOrder": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow Clients.SaveODataOrder": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow Clients.SaveOrder": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow CommitActivity.CommitNoEventsWithRefresh": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow CommitActivity.DefaultCommit": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow FeedbackModule.ConvertBase64String": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow FeedbackModule.ConvertUUIDToURL": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow FeedbackModule.PopulateUserAttributes": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow FeedbackModule.SUB_Feedback_PostToAppInsights": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow FeedbackModule.SUB_Feedback_Sanitize": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow FeedbackModule.SUB_Feedback_SendToServer": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow FeedbackModule.VAL_Feedback": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow Mappings.ImportItems": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow Mappings.PostBinary": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow Mappings.PostCustomRequestTemplate": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow Mappings.PostCustomRequestTemplate_2": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow Mappings.PostExportMapping": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow Mappings.PostFormData": {laws: []law{lawExec}, issue: "#721", why: "microflow: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow Microflows.MicroflowReduce": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow Microflows.SplitMerge": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow MyFirstModule.MyFirstLogic": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow MyFirstModule.RetrieveExamples": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow MyFirstModule.ZzMxcliProbe_Boolean": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow MyFirstModule.ZzMxcliProbe_Entity": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow MyFirstModule.ZzMxcliProbe_List": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow MyFirstModule.ZzMxcliProbe_LoopSplit": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow MyFirstModule.ZzMxcliProbe_Trivial": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow Odata.UnboundedActionMF": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow Odata.UnboundedActionMF2": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow Rules.MicroflowUsingRule": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow Services.GetCustomerOrders": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow Services.GetOrder": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow Services.SaveOrder": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_Attachment_Create": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_Attachment_Download": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_Attachment_Save": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_Attachment_Save_Admin": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_Comment_Delete": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_ConflictedWorkflowDefinitionView_Show": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_ConflictedWorkflowHelper_ApplyJumpTo": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_ConflictedWorkflowHelper_Workflow_Abort": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_ConflictedWorkflowHelper_Workflow_Continue": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_ConflictedWorkflowHelper_Workflow_JumpTo": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_ConflictedWorkflowHelper_Workflow_Restart": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_ConflictedWorkflowView_ShowWorkflowAdminPage": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_DashboardContext_Refresh": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_MyInitiatedWorkflowView_WithdrawWorkflow": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_TaskAssignmentHelper_Reassign": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_TaskAssignmentHelper_Reassign_Show": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_TaskAssignmentHelper_Retarget": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_TaskAssignmentHelper_Retarget_Show": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_TaskAssignmentHelper_Unassign": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_TaskAssignmentHelper_Unassign_Show": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_TaskAssignment_Show": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_TaskCount_Update": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_UserTaskView_Migrate": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_UserTask_AssignToMe": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_UserTask_AssignToMe_UpdateTaskCount": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_UserTask_AssignToUser": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_UserTask_AssignToUsers": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_UserTask_ShowDefaultAdminPage": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_UserTask_Unassign": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_User_WorkflowGroups_Add": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_User_WorkflowGroups_Remove": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_WorkflowCommentHelper_Edit_Save": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_WorkflowCommentHelper_SaveNew": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_WorkflowCommentHelper_SaveNew_Admin": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_WorkflowComment_Edit": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_WorkflowComment_Withdraw": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_WorkflowDefinitionHelper_ShowLockPage": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_WorkflowDefinitionHelper_ShowUnlockPage": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_WorkflowDefinition_CleanUp_Execute": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_WorkflowDefinition_CleanUp_Open": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_WorkflowDefinition_CloseActionConfirmation": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_WorkflowDefinition_Delete": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_WorkflowDefinition_Lock": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_WorkflowDefinition_Unlock": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_WorkflowGroupView_WorkflowGroup_Edit": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_WorkflowGroup_Users_Add": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_WorkflowGroup_Users_Remove": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_WorkflowJumpToDetails_Apply": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_WorkflowSubProcess_ShowDefaultAdminPage": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_WorkflowSummary": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_WorkflowUserTaskView_ShowDefaultAdminPage": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_WorkflowUserTaskView_ShowUserTaskPage": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_WorkflowUserTask_Assign": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_WorkflowUserTask_Assignees_Add": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_WorkflowUserTask_Assignees_Remove": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_WorkflowUserTask_TargetGroups_Add": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_WorkflowUserTask_TargetGroups_Remove": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_WorkflowUserTask_TargetUsers_Add": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_WorkflowUserTask_TargetUsers_Remove": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_WorkflowUserTask_Unassign": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_Workflow_Abort": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_Workflow_CloseActionConfirmation": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_Workflow_Continue": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_Workflow_JumpTo": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_Workflow_OpenParentWorkflow": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_Workflow_Pause": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_Workflow_Restart": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_Workflow_Retry": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_Workflow_Retry_KeepTargetedUsers": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_Workflow_Retry_RerunUserTargeting": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_Workflow_ShowWorkflowAdminPage": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ACT_Workflow_Unpause": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.ASU_UserTaskView_Migrate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.DS_Configuration": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.DS_ConflictedWorkflowView_ShowActionOptions": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.DS_MyInitiatedWorkflowView_TimelineViewer": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.DS_TaskAssignmentHelper_Account": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.DS_TaskCount": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.DS_TaskCount_Admin": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.DS_TaskDashboard": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.DS_TaskSeries": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.DS_TimelineViewer_WorkflowActivityRecords_Full": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.DS_TimelineViewer_WorkflowActivityRecords_Tasks": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.DS_WorkflowCommentHelper_InitializeNew": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.DS_WorkflowCurrentActivity_Options": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.DS_WorkflowDashboard": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.DS_WorkflowDefinition_Overview": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.DS_WorkflowDefinition_SelectableImplementation": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.DS_WorkflowSeries": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.DS_WorkflowTaskDefinition_Selectable_Administrator": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.DS_WorkflowTaskDefinition_Selectable_UserImplementation": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.DS_WorkflowTaskDetail": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.DS_WorkflowTask_AssignedToUser_Timeline": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.DashboardContext_GetSelectedWorkflowDefinition": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.DashboardContext_GetSelectedWorkflowTaskDefinition": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.OCH_Assignee_Search": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.OCH_CleanupHelper_UpdateCount": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.OCH_DashboardContext_UpdateTaskDashboard": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.OCH_DashboardContext_UpdateWorkflowDashboard": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SE_WorkflowAuditTrailRecord_CleanUp": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_CleanupHelper_Execute": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_CleanupHelper_Validate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_Configuration_FindOrCreate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_ConflictReasonGroup_FindOrCreate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_ConflictedWorkflowDefinitionView_UpdateConflictGroups": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_CurrentActivitiesGroup_FindOrCreate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_DashboardContext_RetrieveOrCreate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_DashboardContext_UpdateSettings": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_DashboardContext_UpdateWorkflowDashboard": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_ExecutionPathGroup_FindOrCreate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_TaskAssignmentHelper_Reassign": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_TaskAssignmentHelper_Retarget": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_TaskAssignmentHelper_TaskCount": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_TaskAssignmentHelper_Unassign": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_TaskCount_Update": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_TaskDashboard_Update": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_TaskSeriesList_Delete": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_TaskSeries_CreateOrUpdate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_TaskSummary_CreateOrUpdate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_TaskSummary_RetrieveOrCreate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_UserTaskOutcome_AssignedToUser_Completed": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_UserTaskOutcome_AssignedToUser_InProgress": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_UserTaskViewMigration_Verify": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_UserTaskView_Migrate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_UserTaskView_MigrateToWorkflowEndedUserTask": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_UserTask_Assign": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_UserTask_Assignee_Add": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_UserTask_Assignee_Remove": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_UserTask_Assignees_Add": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_UserTask_Assignees_Remove": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_UserTask_AverageHandlingTime": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_UserTask_CountAlmostDue": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_UserTask_CountCompleted": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_UserTask_CountCompletedOnTime": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_UserTask_CountCompletedOverdue": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_UserTask_CountFailed": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_UserTask_CountInProgress": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_UserTask_CountOverdue": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_UserTask_TargetGroups_Add": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_UserTask_TargetGroups_Remove": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_UserTask_TargetUser_Add": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_UserTask_TargetUser_Remove": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_UserTask_TargetUsers_Add": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_UserTask_TargetUsers_Remove": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_WorkflowAuditTrailRecord_CleanUp": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_WorkflowAuditTrailRecord_DeleteByKey": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_WorkflowDashboard_Update": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_WorkflowDefinitionHelper_FindOrCreate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_WorkflowEvent_AuditTrail": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_WorkflowJumpToDetails_Validate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_WorkflowSeriesList_Delete": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_WorkflowSeries_CreateOrUpdate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_WorkflowSummary_CreateOrUpdate": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_WorkflowSummary_RetrieveOrCreate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_WorkflowTaskDetail_CreateOrUpdate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_WorkflowTaskDetail_Delete": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_WorkflowTaskTimeline_Completed": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_WorkflowTaskTimeline_InProgress": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_WorkflowTask_AverageHandlingTime": {laws: []law{lawParse}, issue: "#721", why: "microflow: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_Workflow_AverageHandlingTime": {laws: []law{lawParse}, issue: "#721", why: "microflow: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_Workflow_CleanUpConflictGroups": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_Workflow_CommentAttachment_Validate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_Workflow_CountAlmostDue": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_Workflow_CountCompleted": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_Workflow_CountCompletedOnTime": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_Workflow_CountCompletedOverdue": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_Workflow_CountInProgress": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_Workflow_CountOverdue": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_Workflow_CurrentUserHasAccess": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_Workflow_Retry": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_Workflow_ShowWorkflowAdminPage": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_Workflow_UpdateConflictGroups": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_Workflow_UpdateConflictReasonGroup": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_Workflow_UpdateConflictResolutionEntities": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_Workflow_UpdateCurrentActivitiesGroup": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_Workflow_UpdateExecutionPathGroup": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.WFEH_WorkflowEvent_AuditTrail": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow workflow.InvokeAgent": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow workflow.UserTaskEventHandle": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow workflow.WorkflowEventHandle": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "nanoflow Atlas_Web_Content.ACT_Login": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "nanoflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "nanoflow Atlas_Web_Content.DS_LoginContext": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "nanoflow FeedbackModule.ACT_Feedback_ClearForm": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "nanoflow FeedbackModule.ACT_Feedback_ClearImage": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "nanoflow FeedbackModule.ACT_Feedback_TriggerScreenshotMode": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "nanoflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "nanoflow FeedbackModule.ACT_Feedback_UploadImage": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "nanoflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "nanoflow FeedbackModule.ACT_Open_Feedback_Modal": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "nanoflow FeedbackModule.ACT_SubmitFeedback": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "nanoflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "nanoflow FeedbackModule.DS_Feedback_Populate": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "nanoflow FeedbackModule.Get_And_Set_Feedback_NPE": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "nanoflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "nanoflow FeedbackModule.OCH_Feedback_SaveToLocalStorage": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "nanoflow FeedbackModule.SUB_Feedback_GetOrCreate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "nanoflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "nanoflow FeedbackModule.SUB_Feedback_ResetLocalStorage": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "nanoflow MyFirstModule.Nanoflow": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "nanoflow WorkflowCommons.ACT_AuditTrailViewer_All": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "nanoflow WorkflowCommons.ACT_AuditTrailViewer_Default": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "nanoflow WorkflowCommons.ACT_AuditTrailViewer_Minimal": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "nanoflow WorkflowCommons.ACT_ConflictedWorkflowDefinitionView_Refresh": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "nanoflow WorkflowCommons.ACT_DoNothing": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "nanoflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "nanoflow WorkflowCommons.ACT_TaskCount_Refresh": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "nanoflow WorkflowCommons.ACT_TimelineViewer_OpenSubWorkflow": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "nanoflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "nanoflow WorkflowCommons.ACT_TimelineViewer_OpenWorkflow": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "nanoflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "nanoflow WorkflowCommons.ACT_WorkflowAuditTrailRecord_ExportToExcel": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "nanoflow WorkflowCommons.ACT_WorkflowAuditTrailRecord_Refresh": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "nanoflow WorkflowCommons.ACT_WorkflowComment_Withdraw_Confirm": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "nanoflow WorkflowCommons.DS_AuditTrailViewer": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "nanoflow WorkflowCommons.DS_MyInitiatedWorkflowView_LoadNotificationArea": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "nanoflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "nanoflow WorkflowCommons.DS_WorkflowActivityRecord_ActivityDuration": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "nanoflow WorkflowCommons.DS_WorkflowTask_LoadNotificationArea": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "nanoflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "nanoflow WorkflowCommons.DS_WorkflowUserTask_AssigneeHelper": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "nanoflow WorkflowCommons.DS_Workflow_LoadNotificationArea": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "nanoflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "nanoflow WorkflowCommons.DS_Workflow_TimelineViewer": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "nanoflow WorkflowCommons.OCH_WorkflowCurrentActivity_Target": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "nanoflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "nanoflow WorkflowCommons.SUB_AuditTrailViewer_Default": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "nanoflow WorkflowCommons.SUB_Duration_Calculate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "nanoflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "odata client Clients.OrderODataClient": {laws: []law{lawExec}, issue: "#743", why: "plain create refused until the rewrite carries UseQuerySegment, catalog, proxy and microflow settings and the icon"}, + "odata client Odata.Bug1073": {laws: []law{lawExec}, issue: "#743", why: "plain create refused until the rewrite carries UseQuerySegment, catalog, proxy and microflow settings and the icon"}, + "page Administration.Account_Edit": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page Administration.Account_New": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page Administration.Account_Overview": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page Administration.ActiveSessions": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page Administration.ChangeMyPasswordForm": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page Administration.ChangePasswordForm": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page Administration.MyAccount": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page Administration.RuntimeInstances": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page Administration.ScheduledEvents": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page FeedbackModule.PopupFailure": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page FeedbackModule.PopupFailure_Logo": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page FeedbackModule.PopupSuccess": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page FeedbackModule.PopupSuccess_Logo": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page FeedbackModule.ShareFeedback": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page FeedbackModule.ShareFeedback_Logo": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page MyFirstModule.Home_Web": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page Pages.EditableLIstView": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page Pages.Vehicle_Overview": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page Rules.BusinessRule_NewEdit": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page Rules.BusinessRule_Overview": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "page: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page Rules.RuleAction_NewEdit": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page Rules.RuleAction_Overview": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "page: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page Rules.RuleCategory_NewEdit": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page Rules.RuleCategory_Overview": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "page: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.ConflictResolution": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "page: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.ConflictedActivitiesHelper_JumpTo_Options": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.ConflictedWorkflowDefinitionView": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "page: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.ConflictedWorkflowDefinitionView_ActionConfirmation": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.DefaultWorkflowAdmin": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.ManageTaskAssignments": {laws: []law{lawExec}, issue: "#721", why: "page: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.MyInitiatedWorkflowView_WithdrawConfirmation": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.MyInitiatedWorkflows": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.TaskAssignmentHelper_UserTask_Reassign": {laws: []law{lawExec}, issue: "#721", why: "page: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.TaskAssignmentHelper_UserTask_Reassign_TargetUserOptions": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.TaskAssignmentHelper_UserTask_Retarget": {laws: []law{lawExec}, issue: "#721", why: "page: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.TaskAssignmentHelper_UserTask_Retarget_TargetUserOptions": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.TaskAssignmentHelper_UserTask_Unassign_TargetUserOptions": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.TaskDashboard": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "page: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.TaskInbox": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "page: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.UserTask_Assign": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "page: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.UserTask_Target": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.UserTask_TargetGroups": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.User_WorkflowGroup_Select": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.WorkflowAdminCenter": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.WorkflowAttachment_New": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "page: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.WorkflowAttachment_View": {laws: []law{lawExec}, issue: "#721", why: "page: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.WorkflowAuditTrailRecord_Overview": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.WorkflowCommentHelper_Edit": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.WorkflowComment_Edit_Admin": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.WorkflowDefinition_CleanUp": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.WorkflowDefinition_CleanUp_Preview": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.WorkflowDefinition_Lock": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.WorkflowDefinition_Overview": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.WorkflowDefinition_Unlock": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.WorkflowDefinition_View": {laws: []law{lawExec}, issue: "#721", why: "page: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.WorkflowEndedUserTask": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.WorkflowGroup_Edit": {laws: []law{lawExec}, issue: "#721", why: "page: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.WorkflowGroup_Overview": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.WorkflowGroup_User_Select": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.WorkflowSubProcess_View": {laws: []law{lawExec}, issue: "#721", why: "page: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.WorkflowUserTaskView_View": {laws: []law{lawExec}, issue: "#721", why: "page: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.Workflow_Dashboard": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.Workflow_JumpTo_Options": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page workflow.MultiUserTaskPage": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page workflow.UserTaskPage": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "published rest service Services.OrdersRestApi": {laws: []law{lawGetPut}, issue: "#721", why: "published rest service: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "rest client Clients.OrdersRestClient": {laws: []law{lawParse}, issue: "#721", why: "rest client: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "rest client Mappings.RestClient": {laws: []law{lawParse}, issue: "#721", why: "rest client: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "rule Rules.Rule1": {laws: []law{lawGetPut}, issue: "#721", why: "rule: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "rule Rules.Rule2": {laws: []law{lawGetPut}, issue: "#721", why: "rule: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "scheduled event WorkflowCommons.SE_WorkflowAuditTrailRecord_CleanUp": {laws: []law{lawGetPut}, issue: "#721", why: "scheduled event: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet Administration.ReadMe": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet Atlas_Core.FeedbackWidget": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet Atlas_Core.LanguageSelectorWidget": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet Rules.Entity_Menu": {laws: []law{lawParse}, issue: "#721", why: "snippet: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Readme": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Account_InactiveIndicator": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Assignee_Search": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_AuditTrailViewer_Toolbar": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_DashboardContext_Timeline": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_MyInitiatedWorkflowView_ActivityTimelineOnly_Tasks": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_MyInitiatedWorkflowView_NotificationArea": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_MyInitiatedWorkflowView_State": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_MyInitiatedWorkflowView_StateCircleOnly": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_MyInitiatedWorkflowView_TaskTimeLineOnly": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_MyInitiatedWorkflowView_TaskTimeline_WithoutName": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_TaskAssignmentHelper_Assignee_Search": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_TaskAssignmentHelper_TargetUser_Search": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_TaskAssignment_UserTask_Assignees": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_TaskAssignment_UserTask_TargetUsers": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_TaskCount_RefreshBTN": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_TaskDashboard_Header": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_TaskDashboard_Numbers": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_TimelineViewer_Timeline_Full": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_TimelineViewer_Timeline_Tasks": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_UserTask_Assignees": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_UserTask_AttachmentAndComments": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_UserTask_Detail": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_UserTask_DueDate": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_UserTask_DueDate_Warning": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_UserTask_Header": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_UserTask_NameColumn": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_UserTask_NameColumnWithIcon": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_UserTask_NotificationArea": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_UserTask_State": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_UserTask_TargetGroups": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_UserTask_TargetUsers": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_UserTask_TaskTimeline": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_UserTask_UnassignedMessage": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowActivityRecord_ActivityIcon": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowActivityRecord_Details": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowActivityRecord_Header": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowActivityRecord_TaskDueDate": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowActivityRecord_TaskDueDate_Warning": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowActivity_Details_ActivityType": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowAuditTrailRecord_Overview": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowDashboard_Header": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowDashboard_TaskNumbers": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowDashboard_WorkflowNumbers": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowDefinition_Actions": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowDefinition_AuditTrail": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowDefinition_Header": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowEndedUserTask_Assignees": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowEndedUserTask_Header": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowEndedUserTask_State": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowEndedUserTask_TargetGroups": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowEndedUserTask_TargetUsers": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowGroup_Overview": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowJumpToDetails": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowSubProcess_Details": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowSubProcess_IncompatibleWarning": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowSubProcess_State": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowUserTaskView_Assignees": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowUserTaskView_Details": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowUserTaskView_DueDate": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowUserTaskView_DueDate_Warning": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowUserTaskView_IncompatibleWarning": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowUserTaskView_NameColumn": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowUserTaskView_NameColumnWithIcon": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowUserTaskView_State": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowUserTask_IncompatibleWarning": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Workflow_ActivityTimeline": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Workflow_ActivityTimelineOnly_Full": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Workflow_ActivityTimelineOnly_Tasks": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Workflow_AuditTrail": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Workflow_CommentsAndAttachments": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Workflow_CommentsAndAttachments_Admin": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Workflow_Detail": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Workflow_DueDate_Warning": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Workflow_Header": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Workflow_MoreActions": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Workflow_NotificationArea": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Workflow_State": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Workflow_StateCircleOnly": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Workflow_SubProcessDetails": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Workflow_TaskDetails": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Workflow_TaskTimeLineOnly": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Workflow_TaskTimeline": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Workflow_TaskTimeline_WithoutName": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "workflow workflow.Workflow1": {laws: []law{lawExec}, issue: "#743", why: "plain create refused until the rewrite carries event sub-processes, outcome flows and activity names"}, + "workflow workflow.Workflow1_2": {laws: []law{lawExec}, issue: "#743", why: "plain create refused until the rewrite carries event sub-processes, outcome flows and activity names"}, +} + +// createOrModifyProbeKnownFailures is the allowlist of +// TestTestAppCreateOrModifyProbe. It may only shrink; a kind switches its +// describe verb once none of its documents is listed here. +var createOrModifyProbeKnownFailures = map[string]knownFailure{ + "external entity Clients.Orders": {laws: []law{lawGetPut}, issue: "#721", why: "only the NoGeneralization HasXAttr=false flags are dropped (#721 B)"}, + "external entity Odata.Devices": {laws: []law{lawGetPut}, issue: "#721", why: "only the NoGeneralization HasXAttr=false flags are dropped (#721 B)"}, + "odata client Clients.OrderODataClient": {laws: []law{lawGetPut}, issue: "#743", why: "UseQuerySegment, ApplicationId, EndpointId, CatalogUrl, Icon, proxy and microflow settings dropped; list markers"}, + "odata client Odata.Bug1073": {laws: []law{lawGetPut}, issue: "#743", why: "UseQuerySegment, ApplicationId, EndpointId, CatalogUrl, Icon, proxy and microflow settings dropped; list markers"}, + "workflow workflow.Workflow1": {laws: []law{lawGetPut}, issue: "#743", why: "event sub-processes, outcome flows, activity names and sizes dropped"}, + "workflow workflow.Workflow1_2": {laws: []law{lawGetPut}, issue: "#743", why: "event sub-processes, outcome flows, activity names and sizes dropped"}, +} diff --git a/mdl/roundtrip/testapp_create_or_modify_test.go b/mdl/roundtrip/testapp_create_or_modify_test.go new file mode 100644 index 000000000..ea53fadc5 --- /dev/null +++ b/mdl/roundtrip/testapp_create_or_modify_test.go @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: Apache-2.0 + +//go:build integration + +package roundtrip + +import ( + "regexp" + "strings" + "testing" +) + +// deferredVerbKinds are the document kinds whose describe still prints a plain +// `create` (#743): until a `create or modify` rewrite carries everything +// describe cannot print, the plain verb refuses on an existing document rather +// than silently losing Studio Pro-authored content (ADR-0012: carry or refuse). +// +// TestTestAppCreateOrModifyProbe is the evidence for switching a kind: it runs +// each such document's describe output with the verb rewritten to `create or +// modify`, on the Studio Pro-authored TestApp, and holds it to the same laws. +// A kind may switch its describe verb once none of its documents is listed in +// createOrModifyProbeKnownFailures; the entry is then struck, and the main +// round trip (TestTestAppRoundTrip) covers it from then on. +// +// `odata service` switched in #743: its probe passed on all three TestApp +// services once the rewrite carried ExportLevel, PageSize, the entity-set order +// and CanBeEmpty. +var deferredVerbKinds = map[string]bool{ + "workflow": true, + "odata client": true, + "external entity": true, +} + +// createOrModifyProbeKnownFailures lives in testapp_allowlist_test.go. + +var leadingCreate = regexp.MustCompile(`(?m)^create (workflow|odata client|external entity) `) + +// asCreateOrModify rewrites each top-level plain `create ` of a deferred +// kind to `create or modify `. +func asCreateOrModify(script string) string { + return leadingCreate.ReplaceAllString(script, "create or modify $1 ") +} + +func TestTestAppCreateOrModifyProbe(t *testing.T) { + h := newFixtureHarness(t, testApp) + defer h.close() + + probed := 0 + seen := map[string]bool{} + for _, d := range h.documents() { + if !deferredVerbKinds[d.keyword] { + continue + } + key := d.key() + seen[key] = true + t.Run(key, func(t *testing.T) { + first, err := h.describe(d.target()) + if err != nil { + t.Fatalf("describe %s: %v", key, err) + } + if !leadingCreate.MatchString(first) { + if strings.Contains(first, "create or modify "+d.keyword+" ") { + t.Fatalf("describe %s already prints `create or modify` — remove %q from deferredVerbKinds; TestTestAppRoundTrip covers it now", key, d.keyword) + } + t.Fatalf("describe %s printed no `create %s` to probe:\n%s", key, d.keyword, first) + } + probed++ + judge(t, createOrModifyProbeKnownFailures, key, h.roundTripWith(d, asCreateOrModify)) + }) + } + // A probe that looked at nothing proves nothing: TestApp has documents of + // every deferred kind. + if probed == 0 { + t.Errorf("probed no documents — the enumeration of %v is broken", deferredVerbKinds) + } + for key := range createOrModifyProbeKnownFailures { + if !seen[key] { + t.Errorf("createOrModifyProbeKnownFailures lists %q, which TestApp does not contain — stale entry, remove it", key) + } + } +} + +// The rewrite is the probe's only lever, so it is pinned: it must turn the +// statement's own verb and nothing inside it. +func TestAsCreateOrModify(t *testing.T) { + in := "-- Workflow: M.W\n\ncreate workflow M.W\n display 'create workflow x'\nbegin\nend workflow;\n" + want := "-- Workflow: M.W\n\ncreate or modify workflow M.W\n display 'create workflow x'\nbegin\nend workflow;\n" + if got := asCreateOrModify(in); got != want { + t.Errorf("asCreateOrModify:\n%s\nwant\n%s", got, want) + } + if got := asCreateOrModify("create or modify odata client M.S (\n);\n"); got != "create or modify odata client M.S (\n);\n" { + t.Errorf("an existing `create or modify` was rewritten: %q", got) + } +} diff --git a/testdata/testapp b/testdata/testapp new file mode 160000 index 000000000..11a8fcacd --- /dev/null +++ b/testdata/testapp @@ -0,0 +1 @@ +Subproject commit 11a8fcacd9de33f4f18457734540ba7402f5c2c0 From de4f8e8b14179937248d7af4e05fd5355065792a Mon Sep 17 00:00:00 2001 From: Ako Date: Sun, 27 Sep 2026 14:47:20 +0000 Subject: [PATCH 07/13] executor: extract alter microflow's operation loop into alterFlowContext.apply A pure refactor so create or modify can apply a derived patch through the same checks and splice an alter statement uses (#747). No behaviour change. Co-Authored-By: Claude Opus 5.5 --- mdl/executor/cmd_alter_flow.go | 37 +++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/mdl/executor/cmd_alter_flow.go b/mdl/executor/cmd_alter_flow.go index d8aac4309..a2deb95ac 100644 --- a/mdl/executor/cmd_alter_flow.go +++ b/mdl/executor/cmd_alter_flow.go @@ -45,31 +45,48 @@ func execAlterFlow(ctx *ExecContext, s *ast.AlterFlowStmt) error { targets[i] = c } + mut, err := a.apply(ctx, s.Operations, targets) + if err != nil { + return err + } + if err := mut.Save(); err != nil { + return mdlerrors.NewBackend("save altered "+s.Kind(), err) + } + fmt.Fprintf(ctx.Output, "Altered %s %s\n", s.Kind(), s.Name) + return nil +} + +// apply opens the stored flow for splicing and applies ops, each aimed at the +// candidate at the same index of targets (resolved against the flow as stored). +// It returns the mutator unsaved: the caller saves, or discards it on error so +// nothing is written. +func (a *alterFlowContext) apply(ctx *ExecContext, ops []*ast.AlterFlowOperation, targets []mfmutator.Candidate) (backend.MicroflowMutator, error) { + s := a.stmt mut, err := ctx.Backend.OpenMicroflowForMutation(a.mf.ID) if err != nil { - return mdlerrors.NewBackend("open "+s.Kind()+" for alter", err) + return nil, mdlerrors.NewBackend("open "+s.Kind()+" for alter", err) } - for i, op := range s.Operations { + for i, op := range ops { target := targets[i] fail := func(err error) error { return mdlerrors.NewValidation(fmt.Sprintf("alter %s %s: %s %s: %v", s.Kind(), s.Name, op.Op, op.Target, err)) } if op.Op == ast.AlterFlowDrop { if err := a.checkOutputUnused(target, nil); err != nil { - return fail(err) + return nil, fail(err) } if err := mut.Drop(target.ID); err != nil { - return fail(err) + return nil, fail(err) } a.noteRemoved(target, nil) continue } frag, err := a.buildFragment(ctx, op.Body) if err != nil { - return fail(err) + return nil, fail(err) } if err := a.checkFragmentScope(ctx, op, target, frag); err != nil { - return fail(err) + return nil, fail(err) } switch op.Op { case ast.AlterFlowInsertAfter: @@ -84,18 +101,14 @@ func execAlterFlow(ctx *ExecContext, s *ast.AlterFlowStmt) error { err = fmt.Errorf("unknown operation") } if err != nil { - return fail(err) + return nil, fail(err) } if op.Op == ast.AlterFlowReplace { a.noteRemoved(target, frag) } a.noteFragment(ctx, frag) } - if err := mut.Save(); err != nil { - return mdlerrors.NewBackend("save altered "+s.Kind(), err) - } - fmt.Fprintf(ctx.Output, "Altered %s %s\n", s.Kind(), s.Name) - return nil + return mut, nil } // alterFlowContext is what the operations of one statement share: the stored From e4d81bd953f3197e3cc42c8a00f28c578c7092e0 Mon Sep 17 00:00:00 2001 From: Ako Date: Sun, 27 Sep 2026 15:08:29 +0000 Subject: [PATCH 08/13] executor: create or modify microflow|nanoflow is diff-then-patch (#747) An existing flow is no longer rebuilt. The stored flow is described and parsed back, compared with the declared definition statement by statement (LCS over declaredMatches, recursing into if branches), and the minimal insert/replace/drop is applied through the #739 splice via the same alterFlowContext an alter statement uses. An unchanged definition writes nothing and reports Unchanged. A change the splice cannot express (header, loop or error-handler body, a moved node) is refused under mdl 1 and still rebuilt under mdl 0 with the MDL-V1-REBUILD warning (ADR-0011). Strikes all #721 class A microflow and nanoflow entries from the PedApp round-trip allowlist and the two nanoflow entries from studioProKnownLossy. Co-Authored-By: Claude Opus 5.5 --- .../skills/mendix/write-microflows/SKILL.md | 16 +- .../skills/mendix/write-nanoflows/SKILL.md | 16 +- mdl/executor/cmd_alter_flow.go | 9 +- mdl/executor/cmd_flow_modify.go | 815 ++++++++++++++++++ mdl/executor/cmd_microflows_create.go | 12 + mdl/executor/cmd_nanoflows_create.go | 15 + mdl/executor/flow_declared_match.go | 137 +++ mdl/executor/flow_declared_match_test.go | 107 +++ mdl/executor/studiopro_roundtrip_test.go | 5 - mdl/roundtrip/allowlist_test.go | 33 - mdl/roundtrip/flow_modify_test.go | 394 +++++++++ 11 files changed, 1507 insertions(+), 52 deletions(-) create mode 100644 mdl/executor/cmd_flow_modify.go create mode 100644 mdl/executor/flow_declared_match.go create mode 100644 mdl/executor/flow_declared_match_test.go create mode 100644 mdl/roundtrip/flow_modify_test.go diff --git a/.claude/skills/mendix/write-microflows/SKILL.md b/.claude/skills/mendix/write-microflows/SKILL.md index ac77a04dd..4f05786ab 100644 --- a/.claude/skills/mendix/write-microflows/SKILL.md +++ b/.claude/skills/mendix/write-microflows/SKILL.md @@ -42,12 +42,16 @@ Choose the mode by who owns the microflow ([choose-edit-mode](../choose-edit-mod - **Created by your MDL scripts, and not edited in Studio Pro since:** edit the script (or fresh `describe` output) and re-run `create or modify`. -- **Authored in Studio Pro:** there is **no `alter microflow` yet**, and re-emitting it - with `create or modify` renumbers element IDs, removes merges and resets connector - curves even for a one-line change. Keep the change minimal: put new logic in a new - sub-microflow and change the existing flow only to call it. Commit first, then - `describe` it again after `exec` and diff it against the original output. Anything - that differs and that you did not change is a loss. +- **Authored in Studio Pro:** prefer `alter microflow X { insert/replace/drop … }` + (targets from `describe microflow X with handles`). `create or modify` of `describe` + output also works as a patch: an unchanged definition writes nothing, and an inserted, + replaced or dropped statement (at the top level or in an `if` branch) is spliced in, + leaving every other node, merge and curve as stored. A change it cannot splice — the + header, anything inside a loop body or error handler, a moved node — rebuilds the + whole microflow under mdl 0 + (warning `MDL-V1-REBUILD`: element IDs renumbered, merges removed, curves reset) and + is refused under `mdl 1;` (header and loop-body changes have no splice yet; move + nodes in Studio Pro). ## When to Use a Microflow vs a Nanoflow diff --git a/.claude/skills/mendix/write-nanoflows/SKILL.md b/.claude/skills/mendix/write-nanoflows/SKILL.md index 1b03588b7..afcae59da 100644 --- a/.claude/skills/mendix/write-nanoflows/SKILL.md +++ b/.claude/skills/mendix/write-nanoflows/SKILL.md @@ -23,12 +23,16 @@ Choose the mode by who owns the nanoflow ([choose-edit-mode](../choose-edit-mode - **Created by your MDL scripts, and not edited in Studio Pro since:** edit the script (or fresh `describe` output) and re-run `create or modify`. -- **Authored in Studio Pro:** there is **no `alter nanoflow` yet**, and re-emitting it - with `create or modify` has dropped annotation links and changed the export level on - Studio Pro nanoflows, even with no edit at all. Keep the change minimal: put new logic - in a new nanoflow and change the existing one only to call it. Commit first, then - `describe` it again after `exec` and diff it against the original output. Anything - that differs and that you did not change is a loss. +- **Authored in Studio Pro:** prefer `alter nanoflow X { insert/replace/drop … }` + (targets by output variable, caption or statement pattern). `create or modify` of `describe` + output also works as a patch: an unchanged definition writes nothing, and an inserted, + replaced or dropped statement (at the top level or in an `if` branch) is spliced in, + leaving every other node, merge and curve as stored. A change it cannot splice — the + header, anything inside a loop body or error handler, a moved node — rebuilds the + whole nanoflow under mdl 0 + (warning `MDL-V1-REBUILD`: element IDs renumbered, merges removed, curves reset) and + is refused under `mdl 1;` (header and loop-body changes have no splice yet; move + nodes in Studio Pro). ## When to Use a Nanoflow vs a Microflow diff --git a/mdl/executor/cmd_alter_flow.go b/mdl/executor/cmd_alter_flow.go index a2deb95ac..7af925184 100644 --- a/mdl/executor/cmd_alter_flow.go +++ b/mdl/executor/cmd_alter_flow.go @@ -128,11 +128,15 @@ type alterFlowContext struct { declaredByOps map[string]bool readByOps map[string][]string removedByOps map[string]bool + // removedIDs are the stored activities earlier operations took out; what + // they read no longer counts as a use. + removedIDs map[model.ID]bool } // noteRemoved records that target's output is gone, unless the fragment that // replaces it declares it again. func (a *alterFlowContext) noteRemoved(target mfmutator.Candidate, replacement *backend.MicroflowFragment) { + a.removedIDs[target.ID] = true v := target.OutputVariable if v == "" || fragmentDeclares(replacement, v) { return @@ -174,7 +178,8 @@ func loadAlterFlow(ctx *ExecContext, s *ast.AlterFlowStmt) (*alterFlowContext, e return nil, mdlerrors.NewBackend("build hierarchy", err) } a := &alterFlowContext{stmt: s, entityNames: getEntityNames(ctx, h), - declaredByOps: map[string]bool{}, readByOps: map[string][]string{}, removedByOps: map[string]bool{}} + declaredByOps: map[string]bool{}, readByOps: map[string][]string{}, removedByOps: map[string]bool{}, + removedIDs: map[model.ID]bool{}} // A copy: nanoflow names are added below, and the cached map is shared. a.microflowNames = map[model.ID]string{} for id, n := range getMicroflowNames(ctx, h) { @@ -500,7 +505,7 @@ func (a *alterFlowContext) checkOutputUnused(target mfmutator.Candidate, replace ref := regexp.MustCompile(`\$` + regexp.QuoteMeta(v) + `\b`) var users []string for _, c := range a.cands { - if c.ID == target.ID { + if c.ID == target.ID || a.removedIDs[c.ID] { continue } for _, text := range append([]string{c.Statement}, c.Alternates...) { diff --git a/mdl/executor/cmd_flow_modify.go b/mdl/executor/cmd_flow_modify.go new file mode 100644 index 000000000..2fdf0c369 --- /dev/null +++ b/mdl/executor/cmd_flow_modify.go @@ -0,0 +1,815 @@ +// SPDX-License-Identifier: Apache-2.0 + +package executor + +import ( + "bytes" + "errors" + "fmt" + "reflect" + "strings" + + "github.com/mendixlabs/mxcli/mdl/ast" + "github.com/mendixlabs/mxcli/mdl/backend/mfmutator" + mdlerrors "github.com/mendixlabs/mxcli/mdl/errors" + "github.com/mendixlabs/mxcli/mdl/langver" + "github.com/mendixlabs/mxcli/mdl/visitor" + "github.com/mendixlabs/mxcli/model" + "github.com/mendixlabs/mxcli/sdk/microflows" +) + +// # create or modify microflow|nanoflow as diff-then-patch (plan item 4.2g) +// +// ADR-0012 decision 3: `create or modify` on a flow that exists compares the +// declared definition with the stored document, derives the minimal patch and +// applies it with the splice engine `alter microflow` uses (mfmutator). An +// empty patch writes nothing. +// +// The stored side is the flow as `describe` prints it, parsed back: that is the +// one rendering of a stored flow MDL already guarantees to re-parse, and it +// puts both sides in the same AST, so "the same definition" is a structural +// comparison rather than a second renderer (the #997 lesson). Statements are +// matched with declaredMatches — the whole statement, so its signature and its +// output variable — by a longest common subsequence; each run of unmatched +// statements between two matched ones becomes one insert, replace or drop, +// aimed at the stored activity by its @position and applied through the same +// alterFlowContext an `alter` statement uses. An `if` that differs only inside +// its branches is diffed branch by branch. +// +// What the splice cannot express — a changed header, a change inside a loop +// body or an error handler, a moved node — is not rebuilt under `mdl 1`: the whole-document rebuild is what reset curves, dropped merges and +// moved element IDs on Studio Pro-authored flows (#721 class A). It is refused +// with the reason instead. Under mdl 0 the rebuild still runs, with the +// MDL-V1-REBUILD warning (ADR-0011: a new refusal applies only under the +// header that opts into it). + +// flowRebuildRefused is the language change: the lossy fallback becomes a +// refusal under mdl 1. It is gated in the executor rather than the visitor +// because whether a statement needs the fallback depends on what is stored, so +// no parse of the script can tell. +var flowRebuildRefused = langver.Change{ + Code: "MDL-V1-REBUILD", + Since: langver.V1, + Old: "`create or modify microflow|nanoflow` rebuilds the whole stored flow when the change cannot be " + + "spliced in, which resets curves, drops merges and renumbers element IDs", + New: "a refusal that names the change the splice cannot make, with nothing written", +} + +// flowDecl is what diff-then-patch needs of a CREATE MICROFLOW or CREATE +// NANOFLOW statement. +type flowDecl struct { + nanoflow bool + name ast.QualifiedName + body []ast.MicroflowStatement + folder string + // header returns the declared and the stored statement with body, folder + // and name cleared, after the rules by which an absent clause keeps what + // is stored have been applied, ready for declaredMatches. + header func(stored ast.Statement) (declared, storedHeader any) +} + +func (d *flowDecl) kind() string { + if d.nanoflow { + return "nanoflow" + } + return "microflow" +} + +// notSpliceable is the reason a declared change has to fall back. +type notSpliceable struct{ reason string } + +func (e *notSpliceable) Error() string { return e.reason } + +func cannotSplice(format string, args ...any) error { + return ¬Spliceable{reason: fmt.Sprintf(format, args...)} +} + +// modifyFlowInPlace applies a `create or modify` of an existing flow as a +// patch. handled is false when the statement is not this path's to apply — no +// such flow yet, or a change the splice cannot make under mdl 0 — and the +// caller then runs the create / rebuild path. +func modifyFlowInPlace(ctx *ExecContext, d *flowDecl) (handled bool, err error) { + if _, err := findModule(ctx, d.name.Module); err != nil { + return false, nil // the create path makes the module + } + alter := &ast.AlterFlowStmt{Nanoflow: d.nanoflow, Name: d.name} + a, err := loadAlterFlow(ctx, alter) + if err != nil { + var nf *mdlerrors.NotFoundError + if errors.As(err, &nf) { + return false, nil // a create + } + return fallBack(ctx, d, cannotSplice("the stored %s cannot be read for splicing: %v", d.kind(), err)) + } + + stored, err := describedFlowStmt(ctx, d, a) + if err != nil { + return fallBack(ctx, d, cannotSplice("its description cannot be compared: %v", err)) + } + decl, storedHeader := d.header(stored) + if !declaredMatches(decl, storedHeader) { + return fallBack(ctx, d, cannotSplice("the header changes (parameters, return type or document properties); "+ + "the splice edits the flow's activities only")) + } + + ops, targets, err := diffFlowBody(a, d.body, storedBody(stored)) + if err != nil { + return fallBack(ctx, d, err) + } + + storedFolder := storedFolderOf(stored) + if len(ops) > 0 { + mut, err := a.apply(ctx, ops, targets) + if err != nil { + return fallBack(ctx, d, cannotSplice("%v", err)) + } + if err := mut.Save(); err != nil { + return true, mdlerrors.NewBackend("save modified "+d.kind(), err) + } + } + containerID := a.mf.ContainerID + if d.folder != storedFolder { + mod, err := findModule(ctx, d.name.Module) + if err != nil { + return true, err + } + to := mod.ID + if d.folder != "" { + if to, err = resolveFolder(ctx, mod.ID, d.folder); err != nil { + return true, mdlerrors.NewBackend("resolve folder "+d.folder, err) + } + } + if _, err := applyDocumentFolder(ctx, a.mf.ID, a.mf.ContainerID, to); err != nil { + return true, err + } + containerID = to + } + + switch { + case len(ops) > 0: + ctx.ReportMutation("Modified", "%s: %s (%s)", d.kind(), d.name, patchSummary(ops)) + case d.folder != storedFolder: + ctx.ReportMutation("Moved", "%s: %s", d.kind(), d.name) + default: + reportUnchanged(ctx, fmt.Sprintf("%s: %s", d.kind(), d.name)) + } + + returnEntity := extractEntityFromReturnType(a.mf.ReturnType) + if d.nanoflow { + ctx.trackCreatedNanoflow(d.name.Module, d.name.Name, a.mf.ID, containerID, returnEntity) + } else { + ctx.trackCreatedMicroflow(d.name.Module, d.name.Name, a.mf.ID, containerID, returnEntity) + } + invalidateHierarchy(ctx) + return true, nil +} + +// fallBack decides what a change the splice cannot make does: refused under +// mdl 1, the whole-document rebuild with a warning under mdl 0. +func fallBack(ctx *ExecContext, d *flowDecl, why error) (bool, error) { + if flowRebuildRefused.Applies(ctx.LanguageVersion) { + return true, mdlerrors.NewValidation(fmt.Sprintf( + "create or modify %s %s: this change cannot be spliced into the stored flow: %v. "+ + "Nothing was written: rebuilding the whole flow instead would reset what Studio Pro drew "+ + "(curves, merges, element IDs). Change activities with `alter %s %s { … }`; "+ + "to rebuild the flow deliberately, drop the %s and create it", + d.kind(), d.name, why, d.kind(), d.name, d.kind())) + } + fmt.Fprintf(ctx.progress(), "Warning [%s]: %s %s is rebuilt as a whole: %v. %s\n", + flowRebuildRefused.Code, d.kind(), d.name, why, flowRebuildRefused.Warning(ctx.LanguageVersion)) + return false, nil +} + +// reportUnchanged reports a statement that wrote nothing, collapsing into the +// run's summary like an elided write does. +func reportUnchanged(ctx *ExecContext, what string) { + line := fmt.Sprintf("Unchanged %s\n", what) + if ctx.tally.countUnchanged(line) { + return + } + fmt.Fprint(ctx.Output, line) +} + +// describedFlowStmt describes the stored flow and parses the description +// under the language version of the script being run, so both sides are read +// by the same rules. See correctAmbiguousRanges for the one stored state the +// description cannot state under mdl 0. +func describedFlowStmt(ctx *ExecContext, d *flowDecl, a *alterFlowContext) (ast.Statement, error) { + var buf bytes.Buffer + prev := ctx.Output + ctx.Output = &buf + var err error + if d.nanoflow { + err = describeNanoflow(ctx, d.name) + } else { + err = describeMicroflow(ctx, d.name) + } + ctx.Output = prev + if err != nil { + return nil, err + } + src := buf.String() + if v := ctx.LanguageVersion; v > langver.V0 { + src = v.String() + ";\n" + src + } + prog, errs := visitor.Build(src) + if len(errs) > 0 { + return nil, fmt.Errorf("the description does not parse: %v", errs[0]) + } + for _, st := range prog.Statements { + switch st.(type) { + case *ast.CreateMicroflowStmt: + if d.nanoflow { + continue + } + case *ast.CreateNanoflowStmt: + if !d.nanoflow { + continue + } + default: + continue + } + if !limitOneIsListUnder(ctx.LanguageVersion) { + correctAmbiguousRanges(st, a.mf.ObjectCollection) + } + return st, nil + } + return nil, fmt.Errorf("the description has no create statement") +} + +// limitOneIsListUnder reports whether `limit 1` reads as a list of one under v +// (the visitor's MDL-V1-LIMIT1 change). +func limitOneIsListUnder(v langver.Version) bool { return v >= langver.V1 } + +// correctAmbiguousRanges fixes the stored side where its mdl 0 description +// says something other than what is stored. +// +// A retrieve with a Custom range of `limit 1` and no offset — a list of one — +// is described as `limit 1`, which mdl 0 reads as the object range +// (ako/mxcli#734): mdl 0 has no spelling for that exact state. Parsed as is, +// the stored side would claim the object range, and a script stating the +// object range would look unchanged against a flow that holds a list; so the +// parsed statement is set back to the list it stands for. The statement is +// found by its output variable and its @position. +func correctAmbiguousRanges(st ast.Statement, oc *microflows.MicroflowObjectCollection) { + type key struct { + v string + p model.Point + } + lists := map[key]bool{} + var collect func(oc *microflows.MicroflowObjectCollection) + collect = func(oc *microflows.MicroflowObjectCollection) { + if oc == nil { + return + } + for _, obj := range oc.Objects { + if loop, ok := obj.(*microflows.LoopedActivity); ok { + collect(loop.ObjectCollection) + continue + } + act, ok := obj.(*microflows.ActionActivity) + if !ok { + continue + } + r, ok := act.Action.(*microflows.RetrieveAction) + if !ok { + continue + } + src, ok := r.Source.(*microflows.DatabaseRetrieveSource) + if !ok || src.Range == nil || src.Range.RangeType != microflows.RangeTypeCustom || + src.Range.Limit != "1" || src.Range.Offset != "" { + continue + } + lists[key{r.OutputVariable, act.Position}] = true + } + } + collect(oc) + if len(lists) == 0 { + return + } + walkStatements(st, func(r *ast.RetrieveStmt) { + if !r.First || r.Annotations == nil || r.Annotations.Position == nil { + return + } + k := key{r.Variable, model.Point{X: r.Annotations.Position.X, Y: r.Annotations.Position.Y}} + if lists[k] { + r.First, r.Limit, r.Offset = false, "1", "" + } + }) +} + +// walkStatements calls fn for every retrieve statement in v, at any depth. +func walkStatements(v any, fn func(*ast.RetrieveStmt)) { + var walk func(rv reflect.Value) + walk = func(rv reflect.Value) { + switch rv.Kind() { + case reflect.Interface: + if !rv.IsNil() { + walk(rv.Elem()) + } + case reflect.Pointer: + if rv.IsNil() { + return + } + if r, ok := rv.Interface().(*ast.RetrieveStmt); ok { + fn(r) + } + walk(rv.Elem()) + case reflect.Struct: + for i := 0; i < rv.NumField(); i++ { + if rv.Type().Field(i).IsExported() { + walk(rv.Field(i)) + } + } + case reflect.Slice, reflect.Array: + for i := 0; i < rv.Len(); i++ { + walk(rv.Index(i)) + } + } + } + walk(reflect.ValueOf(v)) +} + +func storedBody(st ast.Statement) []ast.MicroflowStatement { + switch s := st.(type) { + case *ast.CreateMicroflowStmt: + return s.Body + case *ast.CreateNanoflowStmt: + return s.Body + } + return nil +} + +func storedFolderOf(st ast.Statement) string { + switch s := st.(type) { + case *ast.CreateMicroflowStmt: + return s.Folder + case *ast.CreateNanoflowStmt: + return s.Folder + } + return "" +} + +// microflowDecl adapts a CREATE MICROFLOW statement. +func microflowDecl(s *ast.CreateMicroflowStmt) *flowDecl { + return &flowDecl{ + name: s.Name, body: s.Body, folder: s.Folder, + header: func(stored ast.Statement) (any, any) { + st, _ := stored.(*ast.CreateMicroflowStmt) + if st == nil { + return s, nil + } + dh, sh := *s, *st + for _, h := range []*ast.CreateMicroflowStmt{&dh, &sh} { + h.Body, h.Folder, h.Name, h.CreateOrModify = nil, "", ast.QualifiedName{}, false + } + // Absent means "keep what is stored" for these (see the field + // comments on CreateMicroflowStmt), so absent is not a difference. + if !dh.DocumentationSet { + dh.Documentation = sh.Documentation + } + dh.DocumentationSet, sh.DocumentationSet = false, false + if !dh.Excluded { + dh.Excluded = sh.Excluded + } + if dh.ApplyEntityAccess == nil { + dh.ApplyEntityAccess = sh.ApplyEntityAccess + } + if dh.Expose == nil { + dh.Expose = sh.Expose + } + if dh.URL == nil { + dh.URL = sh.URL + } + if dh.URLSearchParameters == nil { + dh.URLSearchParameters = sh.URLSearchParameters + } + if dh.ExportLevel == nil { + dh.ExportLevel = sh.ExportLevel + } + if dh.Concurrency == nil { + dh.Concurrency = sh.Concurrency + } + return &dh, &sh + }, + } +} + +// nanoflowDecl adapts a CREATE NANOFLOW statement. +func nanoflowDecl(s *ast.CreateNanoflowStmt) *flowDecl { + return &flowDecl{ + nanoflow: true, name: s.Name, body: s.Body, folder: s.Folder, + header: func(stored ast.Statement) (any, any) { + st, _ := stored.(*ast.CreateNanoflowStmt) + if st == nil { + return s, nil + } + dh, sh := *s, *st + for _, h := range []*ast.CreateNanoflowStmt{&dh, &sh} { + h.Body, h.Folder, h.Name, h.CreateOrModify = nil, "", ast.QualifiedName{}, false + } + if !dh.DocumentationSet { + dh.Documentation = sh.Documentation + } + dh.DocumentationSet, sh.DocumentationSet = false, false + if !dh.Excluded { + dh.Excluded = sh.Excluded + } + if dh.Expose == nil { + dh.Expose = sh.Expose + } + return &dh, &sh + }, + } +} + +// diffFlowBody derives the splice operations that turn the stored top-level +// statements into the declared ones. Matched statements are left alone; each +// run of unmatched statements between two matched ones becomes one operation: +// +// - declared statements where none are stored: insert after the stored +// statement before the run (or before the one after it); +// - stored statements where none are declared: drop each; +// - both: replace the first stored one with the declared run, drop the rest. +// +// Targets are the stored activities, located by the @position describe printed +// for each statement. A run whose stored end cannot be located, or that the +// splice cannot express, is a notSpliceable error. +func diffFlowBody(a *alterFlowContext, declared, stored []ast.MicroflowStatement) ([]*ast.AlterFlowOperation, []mfmutator.Candidate, error) { + // Free annotations — notes wired to nothing — belong to the flow, not to + // the statement describe happens to print them above (the first one), so + // they are compared as a whole and kept out of the statement match: an + // insert at the top would otherwise carry them onto a new statement and + // write them a second time. + declared, declaredFree := withoutFreeNotes(declared) + stored, storedFree := withoutFreeNotes(stored) + if !declaredMatches(declaredFree, storedFree) { + return nil, nil, cannotSplice("the free annotations change; the splice edits activities only") + } + + pd := &patchDiff{loc: newStoredLocator(a)} + if err := pd.statements(declared, stored); err != nil { + return nil, nil, err + } + // Drops go last. Each operation's scope check runs against the flow as the + // earlier operations left it, so a stored activity whose output only a + // replaced statement read can be dropped once that statement is replaced, + // and not before. The splice itself does not care about the order: every + // target is a stored activity no other operation touches. + var ops []*ast.AlterFlowOperation + var targets []mfmutator.Candidate + for _, drops := range []bool{false, true} { + for i, op := range pd.ops { + if (op.Op == ast.AlterFlowDrop) == drops { + ops = append(ops, op) + targets = append(targets, pd.targets[i]) + } + } + } + return ops, targets, nil +} + +// patchDiff accumulates the operations of one diff. +type patchDiff struct { + loc *storedLocator + ops []*ast.AlterFlowOperation + targets []mfmutator.Candidate +} + +func (pd *patchDiff) add(op ast.AlterFlowOpKind, c mfmutator.Candidate, body []ast.MicroflowStatement) { + pd.ops = append(pd.ops, &ast.AlterFlowOperation{Op: op, Target: targetLabel(c), Body: body}) + pd.targets = append(pd.targets, c) +} + +// statements diffs one statement list: the flow's top level, or a branch of +// an `if`. The activities in an `if` branch are top-level nodes of the stored +// graph (only a loop nests a collection), so a branch is spliced the same way. +func (pd *patchDiff) statements(declared, stored []ast.MicroflowStatement) error { + pairs := lcsStatements(declared, stored) + di, si := 0, 0 + for p := 0; p <= len(pairs); p++ { + dEnd, sEnd := len(declared), len(stored) + if p < len(pairs) { + dEnd, sEnd = pairs[p][0], pairs[p][1] + } + if err := pd.gap(declared[di:dEnd], stored, si, sEnd); err != nil { + return err + } + if p < len(pairs) { + di, si = pairs[p][0]+1, pairs[p][1]+1 + } + } + return nil +} + +// gap turns one run of unmatched statements — ins declared where stored[si:sEnd] +// is stored — into operations. +func (pd *patchDiff) gap(ins []ast.MicroflowStatement, stored []ast.MicroflowStatement, si, sEnd int) error { + del := stored[si:sEnd] + switch { + case len(ins) == 0 && len(del) == 0: + return nil + case len(del) == 0: + op, c, err := insertAnchor(pd.loc, stored, si, sEnd) + if err != nil { + return err + } + pd.add(op, c, ins) + return nil + } + if len(ins) == 1 && len(del) == 1 { + if d, s, ok := sameIfShell(ins[0], del[0]); ok { + // The same `if` with a change in a branch: splice the branches. + if err := pd.statements(d.ThenBody, s.ThenBody); err != nil { + return err + } + return pd.statements(d.ElseBody, s.ElseBody) + } + if sameIgnoringLayout(ins[0], del[0]) { + p := statementAnnotations(del[0]) + where := "" + if p != nil && p.Position != nil { + where = fmt.Sprintf(" at (%d, %d)", p.Position.X, p.Position.Y) + } + return cannotSplice("the %s%s is moved or its connectors are redrawn; the splice places new nodes only and does not move stored ones", + statementKind(del[0]), where) + } + } + cands := make([]mfmutator.Candidate, len(del)) + for i, st := range del { + c, err := pd.loc.locate(st) + if err != nil { + return err + } + cands[i] = c + } + rest, restStmts := cands, del + if len(ins) > 0 { + body, err := keepStoredNotes(del[0], ins) + if err != nil { + return err + } + pd.add(ast.AlterFlowReplace, cands[0], body) + rest, restStmts = cands[1:], del[1:] + } + for i, c := range rest { + if ann := statementAnnotations(restStmts[i]); ann != nil && len(ann.Notes) > 0 { + return cannotSplice("the %s dropped at (%d, %d) carries an annotation, which would be left behind unattached", + statementKind(restStmts[i]), c.Object.GetPosition().X, c.Object.GetPosition().Y) + } + pd.add(ast.AlterFlowDrop, c, nil) + } + return nil +} + +// sameIfShell reports whether two statements are the same `if` — condition, +// annotations, whether it has an else — differing at most inside its branches. +func sameIfShell(declared, stored ast.MicroflowStatement) (*ast.IfStmt, *ast.IfStmt, bool) { + d, ok1 := declared.(*ast.IfStmt) + s, ok2 := stored.(*ast.IfStmt) + if !ok1 || !ok2 { + return nil, nil, false + } + dShell, sShell := *d, *s + dShell.ThenBody, dShell.ElseBody, sShell.ThenBody, sShell.ElseBody = nil, nil, nil, nil + if !declaredMatches(&dShell, &sShell) { + return nil, nil, false + } + return d, s, true +} + +// keepStoredNotes prepares the declared statements that replace a stored one. +// The splice keeps the stored activity's annotation notes and attaches them to +// the replacement's first activity, so the declared statement must carry the +// same notes — and they are taken off it, or the builder would draw each one a +// second time. A replaced statement with other notes than the stored one is a +// change of annotations, which the splice does not make. +func keepStoredNotes(stored ast.MicroflowStatement, declared []ast.MicroflowStatement) ([]ast.MicroflowStatement, error) { + var storedNotes []ast.MicroflowAnnotation + if ann := statementAnnotations(stored); ann != nil { + storedNotes = ann.Notes + } + if len(storedNotes) == 0 { + return declared, nil + } + var declaredNotes []ast.MicroflowAnnotation + if ann := statementAnnotations(declared[0]); ann != nil { + declaredNotes = ann.Notes + } + if !declaredMatches(declaredNotes, storedNotes) { + return nil, cannotSplice("the annotations on the replaced %s change; the splice keeps a replaced activity's notes as stored", + statementKind(stored)) + } + out := append([]ast.MicroflowStatement(nil), declared...) + out[0] = withAnnotations(declared[0], func(a *ast.ActivityAnnotations) { a.Notes = nil }) + return out, nil +} + +// withoutFreeNotes returns the statements with their free annotations taken +// off (as copies; the script's own statements are not modified, since the +// rebuild may still need them), and the free annotations in order. +func withoutFreeNotes(stmts []ast.MicroflowStatement) ([]ast.MicroflowStatement, []ast.MicroflowAnnotation) { + var free []ast.MicroflowAnnotation + out := make([]ast.MicroflowStatement, len(stmts)) + for i, st := range stmts { + out[i] = st + if ann := statementAnnotations(st); ann != nil && len(ann.FreeNotes) > 0 { + free = append(free, ann.FreeNotes...) + out[i] = withAnnotations(st, func(a *ast.ActivityAnnotations) { a.FreeNotes = nil }) + } + } + return out, free +} + +// withAnnotations returns a shallow copy of st whose annotations are a copy +// edited by edit. st itself is left as it was. +func withAnnotations(st ast.MicroflowStatement, edit func(*ast.ActivityAnnotations)) ast.MicroflowStatement { + v := reflectElem(st) + if !v.IsValid() { + return st + } + cp := reflect.New(v.Type()) + cp.Elem().Set(v) + f := cp.Elem().FieldByName("Annotations") + ann, ok := f.Interface().(*ast.ActivityAnnotations) + if !ok || ann == nil { + return st + } + annCopy := *ann + edit(&annCopy) + f.Set(reflect.ValueOf(&annCopy)) + out, ok := cp.Interface().(ast.MicroflowStatement) + if !ok { + return st + } + return out +} + +// insertAnchor chooses where a run of new statements goes: after the stored +// activity before it when that is an activity (one flow leaves it), else +// before the stored statement after it. gapStart is the index of the first +// stored statement after the run's predecessor; next is the index of the +// matched statement after the run. +func insertAnchor(loc *storedLocator, stored []ast.MicroflowStatement, gapStart, next int) (ast.AlterFlowOpKind, mfmutator.Candidate, error) { + if gapStart > 0 { + if c, err := loc.locate(stored[gapStart-1]); err == nil { + if _, ok := c.Object.(*microflows.ActionActivity); ok { + return ast.AlterFlowInsertAfter, c, nil + } + } + } + if next < len(stored) { + c, err := loc.locate(stored[next]) + if err != nil { + return "", mfmutator.Candidate{}, err + } + return ast.AlterFlowInsertBefore, c, nil + } + if gapStart > 0 { + c, err := loc.locate(stored[gapStart-1]) + if err != nil { + return "", mfmutator.Candidate{}, err + } + return ast.AlterFlowInsertAfter, c, nil + } + return "", mfmutator.Candidate{}, cannotSplice("the stored flow has no statement to insert next to") +} + +// lcsStatements pairs declared and stored statements that match, as a longest +// common subsequence; each pair is {declared index, stored index}, ascending. +func lcsStatements(declared, stored []ast.MicroflowStatement) [][2]int { + n, m := len(declared), len(stored) + eq := make([][]bool, n) + for i := range declared { + eq[i] = make([]bool, m) + for j := range stored { + eq[i][j] = declaredMatches(declared[i], stored[j]) + } + } + // l[i][j] is the LCS length of declared[i:] and stored[j:]. + l := make([][]int, n+1) + for i := range l { + l[i] = make([]int, m+1) + } + for i := n - 1; i >= 0; i-- { + for j := m - 1; j >= 0; j-- { + switch { + case eq[i][j]: + l[i][j] = l[i+1][j+1] + 1 + case l[i+1][j] >= l[i][j+1]: + l[i][j] = l[i+1][j] + default: + l[i][j] = l[i][j+1] + } + } + } + var pairs [][2]int + for i, j := 0, 0; i < n && j < m; { + switch { + case eq[i][j] && l[i][j] == l[i+1][j+1]+1: + pairs = append(pairs, [2]int{i, j}) + i++ + j++ + case l[i+1][j] >= l[i][j+1]: + i++ + default: + j++ + } + } + return pairs +} + +// storedLocator finds the stored activity a statement of the stored flow's +// description stands for. describe prints each activity's @position, which is +// its RelativeMiddlePoint; among the top-level objects that is unique in any +// flow drawn so that nodes do not sit on top of each other. +type storedLocator struct { + byPos map[model.Point][]mfmutator.Candidate +} + +func newStoredLocator(a *alterFlowContext) *storedLocator { + top := map[model.ID]bool{} + for _, obj := range a.mf.ObjectCollection.Objects { + top[obj.GetID()] = true + } + loc := &storedLocator{byPos: map[model.Point][]mfmutator.Candidate{}} + for _, c := range a.cands { + if top[c.ID] && c.Object != nil { + p := c.Object.GetPosition() + loc.byPos[p] = append(loc.byPos[p], c) + } + } + return loc +} + +func (l *storedLocator) locate(st ast.MicroflowStatement) (mfmutator.Candidate, error) { + ann := statementAnnotations(st) + if ann == nil || ann.Position == nil { + return mfmutator.Candidate{}, cannotSplice("the stored statement %q has no activity to address (a join, merge or end of a branch)", statementKind(st)) + } + p := model.Point{X: ann.Position.X, Y: ann.Position.Y} + switch cs := l.byPos[p]; len(cs) { + case 1: + return cs[0], nil + case 0: + return mfmutator.Candidate{}, cannotSplice("no top-level activity is drawn at (%d, %d), where the stored %s is", p.X, p.Y, statementKind(st)) + default: + return mfmutator.Candidate{}, cannotSplice("%d activities are drawn at (%d, %d); cannot tell which one the stored %s is", len(cs), p.X, p.Y, statementKind(st)) + } +} + +// statementAnnotations returns a statement's annotations: every microflow +// statement that has them carries them in a field named Annotations. +func statementAnnotations(st ast.MicroflowStatement) *ast.ActivityAnnotations { + v := reflectElem(st) + if !v.IsValid() { + return nil + } + f := v.FieldByName("Annotations") + if !f.IsValid() { + return nil + } + ann, _ := f.Interface().(*ast.ActivityAnnotations) + return ann +} + +func statementKind(st ast.MicroflowStatement) string { + return strings.TrimSuffix(strings.TrimPrefix(fmt.Sprintf("%T", st), "*ast."), "Stmt") +} + +// targetLabel is how an operation's target is named in a message: its alter +// handle when it has one, else its statement. +func targetLabel(c mfmutator.Candidate) string { + if c.OutputVariable != "" { + return "$" + c.OutputVariable + } + if c.Statement != "" { + return c.Statement + } + return string(c.ID) +} + +// patchSummary says what a patch did, e.g. "1 replaced, 2 inserted". +func patchSummary(ops []*ast.AlterFlowOperation) string { + var ins, rep, drop int + for _, op := range ops { + switch op.Op { + case ast.AlterFlowInsertAfter, ast.AlterFlowInsertBefore: + ins++ + case ast.AlterFlowReplace: + rep++ + case ast.AlterFlowDrop: + drop++ + } + } + var parts []string + for _, p := range []struct { + n int + verb string + }{{ins, "inserted"}, {rep, "replaced"}, {drop, "dropped"}} { + if p.n > 0 { + parts = append(parts, fmt.Sprintf("%d %s", p.n, p.verb)) + } + } + return "spliced: " + strings.Join(parts, ", ") +} diff --git a/mdl/executor/cmd_microflows_create.go b/mdl/executor/cmd_microflows_create.go index ac5e6b36c..664416679 100644 --- a/mdl/executor/cmd_microflows_create.go +++ b/mdl/executor/cmd_microflows_create.go @@ -5,6 +5,7 @@ package executor import ( "fmt" + "strings" "github.com/mendixlabs/mxcli/mdl/ast" mdlerrors "github.com/mendixlabs/mxcli/mdl/errors" @@ -34,6 +35,17 @@ func execCreateMicroflow(ctx *ExecContext, s *ast.CreateMicroflowStmt) error { return mdlerrors.NewNotConnectedWrite() } + // An existing flow is modified as a patch of what is stored, not rebuilt + // (ADR-0012 decision 3); see cmd_flow_modify.go. + if s.CreateOrModify && strings.TrimSpace(s.Name.Name) != "" { + if err := validateMicroflowRules(s); err != nil { + return err + } + if handled, err := modifyFlowInPlace(ctx, microflowDecl(s)); handled || err != nil { + return err + } + } + built, err := buildMicroflowFromStmt(ctx, s, buildFlowOpts{AllowCreate: true}) if err != nil { return err diff --git a/mdl/executor/cmd_nanoflows_create.go b/mdl/executor/cmd_nanoflows_create.go index 7e56a8909..6d56e92d6 100644 --- a/mdl/executor/cmd_nanoflows_create.go +++ b/mdl/executor/cmd_nanoflows_create.go @@ -5,6 +5,7 @@ package executor import ( "fmt" + "strings" "github.com/mendixlabs/mxcli/mdl/ast" mdlerrors "github.com/mendixlabs/mxcli/mdl/errors" @@ -16,6 +17,20 @@ func execCreateNanoflow(ctx *ExecContext, s *ast.CreateNanoflowStmt) error { return mdlerrors.NewNotConnectedWrite() } + // An existing flow is modified as a patch of what is stored, not rebuilt + // (ADR-0012 decision 3); see cmd_flow_modify.go. + if s.CreateOrModify && strings.TrimSpace(s.Name.Name) != "" { + if err := refuseExposeOnFlavour(s.Expose, "nanoflow", s.Name.Module+"."+s.Name.Name); err != nil { + return err + } + if err := validateNanoflowRules(s); err != nil { + return err + } + if handled, err := modifyFlowInPlace(ctx, nanoflowDecl(s)); handled || err != nil { + return err + } + } + built, err := buildNanoflowFromStmt(ctx, s, buildFlowOpts{AllowCreate: true}) if err != nil { return err diff --git a/mdl/executor/flow_declared_match.go b/mdl/executor/flow_declared_match.go new file mode 100644 index 000000000..326d361f5 --- /dev/null +++ b/mdl/executor/flow_declared_match.go @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: Apache-2.0 + +package executor + +import ( + "reflect" + + "github.com/mendixlabs/mxcli/mdl/ast" +) + +// declaredMatches reports whether a declared microflow AST value (from the +// script) states the same thing as the stored flow's AST value (from parsing +// what `describe` prints for it). It is the equality diff-then-patch matches +// statements by (ADR-0012 decision 3; plan item 4.2g). +// +// It is structural equality with one asymmetry: canvas GEOMETRY the script +// leaves out is not a difference. A statement written without `@position`, +// `@curve`, `@anchor`, `@merge` or `@start` has no opinion about where its node +// sits or how its flow bends, so it matches the stored statement wherever that +// is drawn — `create or modify` changes only what differs (R1), and a layout +// nobody stated is not a difference. A statement that DOES state geometry must +// state the stored one: a moved node is a real change, and one the splice does +// not make (it only places new nodes), so it must not pass as unchanged. +// +// Everything else is compared exactly, including captions, colours and notes, +// which are content Studio Pro shows rather than layout. +func declaredMatches(declared, stored any) bool { + return matchValue(reflect.ValueOf(declared), reflect.ValueOf(stored), false) +} + +// sameIgnoringLayout reports whether two statements differ in canvas geometry +// at most — a node moved, a connector redrawn — which is a change the splice +// does not make. +func sameIgnoringLayout(declared, stored any) bool { + return matchValue(reflect.ValueOf(declared), reflect.ValueOf(stored), true) +} + +// The geometry is what stripFlowLayout clears for `mxcli layout flows`; a +// note's size is included here because the writer defaults it when absent. +var ( + annotationsStructType = reflect.TypeOf(ast.ActivityAnnotations{}) + noteStructType = reflect.TypeOf(ast.MicroflowAnnotation{}) + paramStructType = reflect.TypeOf(ast.MicroflowParam{}) +) + +// geometryFields names, per AST type, the fields that hold canvas geometry and +// that a script may therefore leave nil without that being a difference. +var geometryFields = map[reflect.Type]map[string]bool{ + annotationsStructType: { + "Position": true, "Anchor": true, "TrueBranchAnchor": true, "FalseBranchAnchor": true, + "IteratorAnchor": true, "BodyTailAnchor": true, "Curve": true, "Merge": true, "Start": true, + }, + noteStructType: {"Position": true, "Size": true}, + paramStructType: {"Position": true}, +} + +func matchValue(d, s reflect.Value, anyLayout bool) bool { + if !d.IsValid() || !s.IsValid() { + return d.IsValid() == s.IsValid() + } + if d.Type() != s.Type() { + return false + } + switch d.Kind() { + case reflect.Pointer: + if d.IsNil() && s.IsNil() { + return true + } + if d.Type().Elem() == annotationsStructType { + // A statement written with no annotations at all states no + // geometry, and no caption, colour or note either. + if d.IsNil() { + d = reflect.New(annotationsStructType) + } + if s.IsNil() { + s = reflect.New(annotationsStructType) + } + } + if d.IsNil() || s.IsNil() { + return false + } + return matchValue(d.Elem(), s.Elem(), anyLayout) + case reflect.Interface: + if d.IsNil() || s.IsNil() { + return d.IsNil() == s.IsNil() + } + return matchValue(d.Elem(), s.Elem(), anyLayout) + case reflect.Struct: + geo := geometryFields[d.Type()] + for i := 0; i < d.NumField(); i++ { + df := d.Field(i) + if geo[d.Type().Field(i).Name] && df.Kind() == reflect.Pointer && (anyLayout || df.IsNil()) { + continue + } + if !matchValue(df, s.Field(i), anyLayout) { + return false + } + } + return true + case reflect.Slice, reflect.Array: + // nil and empty are the same list. + if d.Len() != s.Len() { + return false + } + for i := 0; i < d.Len(); i++ { + if !matchValue(d.Index(i), s.Index(i), anyLayout) { + return false + } + } + return true + case reflect.Map: + if d.Len() != s.Len() { + return false + } + for _, k := range d.MapKeys() { + sv := s.MapIndex(k) + if !sv.IsValid() || !matchValue(d.MapIndex(k), sv, anyLayout) { + return false + } + } + return true + case reflect.Func, reflect.Chan, reflect.UnsafePointer: + return d.IsNil() == s.IsNil() + default: + return d.Equal(s) + } +} + +// reflectElem returns the struct a statement pointer points at, or the zero +// Value when it is not a pointer to a struct. +func reflectElem(v any) reflect.Value { + rv := reflect.ValueOf(v) + if rv.Kind() != reflect.Pointer || rv.IsNil() || rv.Elem().Kind() != reflect.Struct { + return reflect.Value{} + } + return rv.Elem() +} diff --git a/mdl/executor/flow_declared_match_test.go b/mdl/executor/flow_declared_match_test.go new file mode 100644 index 000000000..425e1b3b3 --- /dev/null +++ b/mdl/executor/flow_declared_match_test.go @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: Apache-2.0 + +package executor + +import ( + "testing" + + "github.com/mendixlabs/mxcli/mdl/ast" + "github.com/mendixlabs/mxcli/mdl/visitor" +) + +func parseFlowBody(t *testing.T, body string) *ast.CreateMicroflowStmt { + t.Helper() + prog, errs := visitor.Build("create or modify microflow M.F ($In: String)\nbegin\n" + body + "\nend;\n") + if len(errs) > 0 { + t.Fatalf("parse: %v", errs[0]) + } + s, ok := prog.Statements[0].(*ast.CreateMicroflowStmt) + if !ok { + t.Fatalf("got %T", prog.Statements[0]) + } + return s +} + +// The stored side is what describe prints: geometry on every statement. +const storedFlowBody = ` @position(200, 200) + @curve(from: (30, 0), to: (-15, 0)) + @caption 'Say hello' + log info node 'N' 'hello'; + @position(400, 200) + if $In = 'x' then + @position(400, 300) + @anchor(from: bottom, to: top) + log info node 'N' 'x'; + end if;` + +func TestDeclaredMatches_OmittedGeometryIsNotADifference(t *testing.T) { + stored := parseFlowBody(t, storedFlowBody) + cases := []struct { + name string + body string + want bool + }{ + {"identical", storedFlowBody, true}, + {"no geometry at all", ` @caption 'Say hello' + log info node 'N' 'hello'; + if $In = 'x' then + log info node 'N' 'x'; + end if;`, true}, + {"a node moved", ` @position(210, 200) + @caption 'Say hello' + log info node 'N' 'hello'; + if $In = 'x' then + log info node 'N' 'x'; + end if;`, false}, + {"a caption dropped", ` log info node 'N' 'hello'; + if $In = 'x' then + log info node 'N' 'x'; + end if;`, false}, + {"a nested statement changed", ` @caption 'Say hello' + log info node 'N' 'hello'; + if $In = 'x' then + log info node 'N' 'y'; + end if;`, false}, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + declared := parseFlowBody(t, tc.body) + if got := declaredMatches(declared.Body, stored.Body); got != tc.want { + t.Errorf("declaredMatches = %v, want %v", got, tc.want) + } + }) + } + + // The asymmetry: geometry the STORED side lacks is not a wildcard. A + // declared position against a stored flow drawn elsewhere is a move. + bare := parseFlowBody(t, ` @caption 'Say hello' + log info node 'N' 'hello';`) + placed := parseFlowBody(t, ` @position(200, 200) + @caption 'Say hello' + log info node 'N' 'hello';`) + if declaredMatches(placed.Body, bare.Body) { + t.Error("a declared @position matched a statement stored without one") + } +} + +func TestLCSStatements_PairsTheUnchangedRuns(t *testing.T) { + stored := parseFlowBody(t, ` log info node 'N' 'a'; + log info node 'N' 'b'; + log info node 'N' 'c'; + log info node 'N' 'd';`) + declared := parseFlowBody(t, ` log info node 'N' 'a'; + log info node 'N' 'new'; + log info node 'N' 'b'; + log info node 'N' 'C'; + log info node 'N' 'd';`) + got := lcsStatements(declared.Body, stored.Body) + want := [][2]int{{0, 0}, {2, 1}, {4, 3}} + if len(got) != len(want) { + t.Fatalf("pairs = %v, want %v", got, want) + } + for i := range want { + if got[i] != want[i] { + t.Fatalf("pairs = %v, want %v", got, want) + } + } +} diff --git a/mdl/executor/studiopro_roundtrip_test.go b/mdl/executor/studiopro_roundtrip_test.go index 9b1be58c4..718a2bca0 100644 --- a/mdl/executor/studiopro_roundtrip_test.go +++ b/mdl/executor/studiopro_roundtrip_test.go @@ -66,11 +66,6 @@ var studioProKnownLossy = map[string]string{ "page Administration.Account_Overview|document": "DataGrid2 object rebuilt from the " + "widget template (property order, column texts, filter captions), layout-grid " + "column weights 12 -> -1, tab-container nulls", - "nanoflow FeedbackModule.ACT_Feedback_UploadImage|document": "activity Size and the " + - "auto-caption 'Activity' are not authorable (upstream #884); a CaseValues-less " + - "flow gains a NoCase", - "nanoflow FeedbackModule.SUB_Feedback_GetOrCreate|document": "the flow builder regenerates merges " + - "(3 ExclusiveMerges -> 1, control flow equivalent), plus activity Size and auto-captions", "association Administration.AccountPasswordData_Account|document": "the domain-model rewrite drops empty " + "MemberAccess refs and NoGeneralization flags (the storage is carried since #704's flip became reachable)", diff --git a/mdl/roundtrip/allowlist_test.go b/mdl/roundtrip/allowlist_test.go index 019cc914b..9ca591be7 100644 --- a/mdl/roundtrip/allowlist_test.go +++ b/mdl/roundtrip/allowlist_test.go @@ -106,39 +106,6 @@ var knownFailures = map[string]knownFailure{ "menu Atlas_Core.Phone_Menu": {laws: []law{lawGetPut}, issue: "#721", why: "nested menu items dropped (#721 E)"}, "menu Atlas_Core.Tablet_Menu": {laws: []law{lawGetPut}, issue: "#721", why: "nested menu items dropped (#721 E)"}, - // #721 A: the microflow rebuild (ADR-0012 decision 3, plan 4.2g). - "microflow Administration.ChangeMyPassword": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "whole-document rebuild: curves, merges, case values (#721 A)"}, - "microflow Administration.ChangePassword": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "whole-document rebuild: curves, merges, case values (#721 A)"}, - "microflow Administration.ManageMyAccount": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "whole-document rebuild: curves, merges, case values (#721 A)"}, - "microflow Administration.NewAccount": {laws: []law{lawGetPut}, issue: "#721", why: "whole-document rebuild: curves, merges, case values (#721 A)"}, - "microflow Administration.NewWebServiceAccount": {laws: []law{lawGetPut}, issue: "#721", why: "whole-document rebuild: curves, merges, case values (#721 A)"}, - "microflow Administration.SaveNewAccount": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "whole-document rebuild: curves, merges, case values (#721 A)"}, - "microflow Administration.ShowMyPasswordForm": {laws: []law{lawGetPut}, issue: "#721", why: "whole-document rebuild: curves, merges, case values (#721 A)"}, - "microflow Administration.ShowPasswordForm": {laws: []law{lawGetPut}, issue: "#721", why: "whole-document rebuild: curves, merges, case values (#721 A)"}, - "microflow FeedbackModule.ConvertBase64String": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "whole-document rebuild: curves, merges, case values (#721 A)"}, - "microflow FeedbackModule.ConvertUUIDToURL": {laws: []law{lawGetPut}, issue: "#721", why: "whole-document rebuild: curves, merges, case values (#721 A)"}, - "microflow FeedbackModule.PopulateUserAttributes": {laws: []law{lawGetPut}, issue: "#721", why: "whole-document rebuild: curves, merges, case values (#721 A)"}, - "microflow FeedbackModule.SUB_Feedback_PostToAppInsights": {laws: []law{lawGetPut}, issue: "#721", why: "whole-document rebuild: curves, merges, case values (#721 A); putget fixed by #718 (expression whitespace)"}, - "microflow FeedbackModule.SUB_Feedback_Sanitize": {laws: []law{lawGetPut}, issue: "#721", why: "whole-document rebuild: curves, merges, case values (#721 A)"}, - "microflow FeedbackModule.SUB_Feedback_SendToServer": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "whole-document rebuild: curves, merges, case values (#721 A)"}, - "microflow FeedbackModule.VAL_Feedback": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "whole-document rebuild: curves, merges, case values (#721 A)"}, - "microflow MyFirstModule.MyFirstLogic": {laws: []law{lawGetPut}, issue: "#721", why: "whole-document rebuild: curves, merges, case values (#721 A)"}, - - // Nanoflows: #705 item 2 plus the rebuild in #721 A. - "nanoflow Atlas_Web_Content.ACT_Login": {laws: []law{lawGetPut, lawPutGet}, issue: "#705 #721", why: "export level and annotations (#705 item 2); whole-document rebuild (#721 A)"}, - "nanoflow Atlas_Web_Content.DS_LoginContext": {laws: []law{lawGetPut}, issue: "#705 #721", why: "export level and annotations (#705 item 2); whole-document rebuild (#721 A)"}, - "nanoflow FeedbackModule.ACT_Feedback_ClearForm": {laws: []law{lawGetPut}, issue: "#705 #721", why: "export level and annotations (#705 item 2); whole-document rebuild (#721 A)"}, - "nanoflow FeedbackModule.ACT_Feedback_ClearImage": {laws: []law{lawGetPut}, issue: "#705 #721", why: "export level and annotations (#705 item 2); whole-document rebuild (#721 A)"}, - "nanoflow FeedbackModule.ACT_Feedback_TriggerScreenshotMode": {laws: []law{lawGetPut, lawPutGet}, issue: "#705 #721", why: "export level and annotations (#705 item 2); whole-document rebuild (#721 A)"}, - "nanoflow FeedbackModule.ACT_Feedback_UploadImage": {laws: []law{lawGetPut, lawPutGet}, issue: "#705 #721", why: "export level and annotations (#705 item 2); whole-document rebuild (#721 A)"}, - "nanoflow FeedbackModule.ACT_Open_Feedback_Modal": {laws: []law{lawGetPut}, issue: "#705 #721", why: "export level and annotations (#705 item 2); whole-document rebuild (#721 A)"}, - "nanoflow FeedbackModule.ACT_SubmitFeedback": {laws: []law{lawGetPut, lawPutGet}, issue: "#705 #721", why: "export level and annotations (#705 item 2); whole-document rebuild (#721 A)"}, - "nanoflow FeedbackModule.DS_Feedback_Populate": {laws: []law{lawGetPut}, issue: "#705 #721", why: "export level and annotations (#705 item 2); whole-document rebuild (#721 A)"}, - "nanoflow FeedbackModule.Get_And_Set_Feedback_NPE": {laws: []law{lawGetPut, lawPutGet}, issue: "#705 #721", why: "export level and annotations (#705 item 2); whole-document rebuild (#721 A)"}, - "nanoflow FeedbackModule.OCH_Feedback_SaveToLocalStorage": {laws: []law{lawGetPut}, issue: "#705 #721", why: "export level and annotations (#705 item 2); whole-document rebuild (#721 A)"}, - "nanoflow FeedbackModule.SUB_Feedback_GetOrCreate": {laws: []law{lawGetPut, lawPutGet}, issue: "#705 #721", why: "export level and annotations (#705 item 2); whole-document rebuild (#721 A)"}, - "nanoflow FeedbackModule.SUB_Feedback_ResetLocalStorage": {laws: []law{lawGetPut}, issue: "#721", why: "whole-document rebuild (#721 A); export level and annotations fixed by #705"}, - // Pages: #705 item 1 plus #721 C. "page Administration.Account_Edit": {laws: []law{lawGetPut}, issue: "#705 #721", why: "texts and translations (#705 item 1); widget properties (#721 C)"}, "page Administration.Account_New": {laws: []law{lawGetPut}, issue: "#705 #721", why: "texts and translations (#705 item 1); widget properties (#721 C)"}, diff --git a/mdl/roundtrip/flow_modify_test.go b/mdl/roundtrip/flow_modify_test.go new file mode 100644 index 000000000..bae87bac1 --- /dev/null +++ b/mdl/roundtrip/flow_modify_test.go @@ -0,0 +1,394 @@ +// SPDX-License-Identifier: Apache-2.0 + +//go:build integration + +package roundtrip + +import ( + "bytes" + "strings" + "testing" + + "go.mongodb.org/mongo-driver/v2/bson" +) + +// ako/mxcli#747 (plan item 4.2g): `create or modify microflow` on an existing +// flow is diff-then-patch on top of the #739 splice. Every flow here is Studio +// Pro-authored (PedApp), because an mxcli-authored flow is laid out the way the +// rebuild lays it out and cannot show what the rebuild loses. + +const valFeedback = "microflow FeedbackModule.VAL_Feedback" + +// An unchanged describe -> create or modify writes nothing: the unit's bytes +// are identical. The controls below prove the same pipeline does write when +// the definition changes. +func TestFlowModify_UnchangedIsByteIdentical(t *testing.T) { + h := newHarness(t) + defer h.close() + + described := h.mustDescribe(t, valFeedback) + before := h.flowUnit(t, "VAL_Feedback") + for _, header := range []string{"", "mdl 1;\n"} { + if err := h.exec(header + described); err != nil { + t.Fatalf("header %q: exec unchanged describe output: %v", header, err) + } + if got := h.flowUnit(t, "VAL_Feedback"); !bytes.Equal(got, before) { + t.Fatalf("header %q: the unchanged definition rewrote the unit", header) + } + if changed := h.orig.diff(h.snapshot()); len(changed) != 0 { + t.Fatalf("header %q: the unchanged definition wrote: %s", header, strings.Join(changed, "; ")) + } + if !strings.Contains(h.out.String(), "Unchanged microflow: FeedbackModule.VAL_Feedback") { + t.Errorf("header %q: want an Unchanged report, got:\n%s", header, h.out.String()) + } + } +} + +// Control: an inserted statement is written, as a splice. Every element the +// stored unit had keeps its $ID and stays in the unit — including the merges +// describe cannot show and the rebuild deleted (#721 A) — and only the new +// activity and one new flow are added. +func TestFlowModify_InsertIsSpliced(t *testing.T) { + h := newHarness(t) + defer h.close() + + described := h.mustDescribe(t, valFeedback) + const anchor = " declare $ValidFeedback Boolean = true;\n" + const inserted = " log info node 'Feedback' 'validating feedback';\n" + edited := strings.Replace(described, anchor, anchor+inserted, 1) + if edited == described { + t.Fatalf("describe output has no %q — the fixture changed:\n%s", anchor, described) + } + before := h.flowUnit(t, "VAL_Feedback") + if err := h.exec(edited); err != nil { + t.Fatalf("exec edited definition: %v", err) + } + if !strings.Contains(h.out.String(), "Modified microflow: FeedbackModule.VAL_Feedback (spliced: 1 inserted)") { + t.Errorf("want a splice report, got:\n%s", h.out.String()) + } + after := h.flowUnit(t, "VAL_Feedback") + if bytes.Equal(after, before) { + t.Fatal("an inserted statement wrote nothing") + } + requireKept(t, before, after, "") + if added := len(elementIDs(t, after)) - len(elementIDs(t, before)); added <= 0 { + t.Errorf("the insert added %d elements", added) + } + if got, want := countType(t, after, "Microflows$ExclusiveMerge"), countType(t, before, "Microflows$ExclusiveMerge"); got != want { + t.Errorf("merges: %d after the insert, %d before — the rebuild ran", got, want) + } + again := h.mustDescribe(t, valFeedback) + if !strings.Contains(again, "log info node 'Feedback' 'validating feedback';") { + t.Errorf("describe does not show the inserted statement:\n%s", again) + } + + // Executing the new description writes nothing more: the splice's own + // output is a fixed point too. + settled := h.flowUnit(t, "VAL_Feedback") + if err := h.exec(again); err != nil { + t.Fatalf("exec the description after the insert: %v", err) + } + if !bytes.Equal(h.flowUnit(t, "VAL_Feedback"), settled) { + t.Error("re-executing the description of the spliced flow rewrote it") + } +} + +// A replaced statement that carries a shared annotation keeps the one stored +// note: the splice re-attaches it, and the declared note is not drawn again. +func TestFlowModify_ReplaceKeepsSharedNote(t *testing.T) { + h := newHarness(t) + defer h.close() + + const target = "microflow FeedbackModule.PopulateUserAttributes" + described := h.mustDescribe(t, target) + const old = "SubmitterDisplayName = $CurrentUser/Name)" + edited := strings.Replace(described, old, "SubmitterDisplayName = 'anonymous')", 1) + if edited == described { + t.Fatalf("describe output has no %q:\n%s", old, described) + } + before := h.flowUnit(t, "PopulateUserAttributes") + if err := h.exec(edited); err != nil { + t.Fatalf("exec edited definition: %v", err) + } + after := h.flowUnit(t, "PopulateUserAttributes") + if bytes.Equal(after, before) { + t.Fatal("a replaced statement wrote nothing") + } + if got := countType(t, after, "Microflows$Annotation"); got != 1 { + t.Errorf("%d annotation notes after the replace, want the 1 stored", got) + } + again := h.mustDescribe(t, target) + if !strings.Contains(again, "SubmitterDisplayName = 'anonymous'") || strings.Count(again, "@annotation(id: n1") != 2 { + t.Errorf("want the new statement with the shared note on both activities:\n%s", again) + } + // Only the replaced activity (and what it contains) is gone. + requireKept(t, before, after, "Microflows$ChangeAction") // ChangeObjectAction's storage name +} + +// Dropping a statement whose output only a statement changed in the same +// definition read: the scope check sees the flow as the replace left it, so +// the drop is not refused for a use that is about to go. +func TestFlowModify_DropAndReplace(t *testing.T) { + h := newHarness(t) + defer h.close() + + const target = "microflow FeedbackModule.SUB_Feedback_Sanitize" + described := h.mustDescribe(t, target) + edited := described + for _, cut := range []string{ + " @position(368, 200)\n @curve(from: (30, 0), to: (-30, 0))\n $SanitizedPageName = call java action FeedbackModule.XSS_Sanitizer(stringToSanitize = $Feedback/PageName);\n", + " PageName = $SanitizedPageName,", + } { + next := strings.Replace(edited, cut, "", 1) + if next == edited { + t.Fatalf("describe output has no %q:\n%s", cut, described) + } + edited = next + } + before := h.flowUnit(t, "SUB_Feedback_Sanitize") + if err := h.exec("mdl 1;\n" + edited); err != nil { + t.Fatalf("exec edited definition: %v", err) + } + if !strings.Contains(h.out.String(), "(spliced: 1 replaced, 1 dropped)") { + t.Errorf("want a splice report, got:\n%s", h.out.String()) + } + after := h.flowUnit(t, "SUB_Feedback_Sanitize") + if got, want := countType(t, after, "Microflows$JavaActionCallAction"), countType(t, before, "Microflows$JavaActionCallAction")-1; got != want { + t.Errorf("%d java action calls after, want %d", got, want) + } + again := h.mustDescribe(t, target) + if strings.Contains(again, "SanitizedPageName") { + t.Errorf("the dropped statement or its use is still described:\n%s", again) + } +} + +// A statement changed inside an `if` branch is spliced too: the branch's +// activities are nodes of the stored graph like any other. +func TestFlowModify_BranchEditIsSpliced(t *testing.T) { + h := newHarness(t) + defer h.close() + + described := h.mustDescribe(t, valFeedback) + const old = "message 'Subject is required';" + edited := strings.Replace(described, old, "message 'A subject is required';", 1) + if edited == described { + t.Fatalf("describe output has no %q:\n%s", old, described) + } + before := h.flowUnit(t, "VAL_Feedback") + for _, header := range []string{"mdl 1;\n", ""} { + if err := h.exec(header + edited); err != nil { + t.Fatalf("header %q: exec edited definition: %v", header, err) + } + } + after := h.flowUnit(t, "VAL_Feedback") + if bytes.Equal(after, before) { + t.Fatal("a statement changed in a branch wrote nothing") + } + // The one replaced activity may go; every other element stays. + if got, want := countType(t, after, "Microflows$ValidationFeedbackAction"), countType(t, before, "Microflows$ValidationFeedbackAction"); got != want { + t.Errorf("%d validation feedback actions after the replace, %d before", got, want) + } + requireKeptBut(t, before, after, "Microflows$ValidationFeedbackAction", "Subject is required") + if got, want := countType(t, after, "Microflows$ExclusiveMerge"), countType(t, before, "Microflows$ExclusiveMerge"); got != want { + t.Errorf("merges: %d after, %d before — the rebuild ran", got, want) + } + if !strings.Contains(h.mustDescribe(t, valFeedback), "'A subject is required'") { + t.Error("describe does not show the change") + } +} + +// A change the splice cannot make — here a node moved — is refused under +// mdl 1 with nothing written, and under mdl 0 still rebuilds, with the +// MDL-V1-REBUILD warning. +func TestFlowModify_UnspliceableChange(t *testing.T) { + h := newHarness(t) + defer h.close() + + described := h.mustDescribe(t, valFeedback) + const old = "@position(-390, 200)" + edited := strings.Replace(described, old, "@position(-380, 200)", 1) + if edited == described { + t.Fatalf("describe output has no %q:\n%s", old, described) + } + + err := h.exec("mdl 1;\n" + edited) + if err == nil || !strings.Contains(err.Error(), "cannot be spliced") || !strings.Contains(err.Error(), "moved") { + t.Fatalf("under mdl 1 want a refusal naming the move, got %v", err) + } + if changed := h.orig.diff(h.snapshot()); len(changed) != 0 { + t.Fatalf("the refused statement wrote: %s", strings.Join(changed, "; ")) + } + + if err := h.exec(edited); err != nil { + t.Fatalf("under mdl 0: %v", err) + } + if !strings.Contains(h.out.String(), "Warning [MDL-V1-REBUILD]") { + t.Errorf("under mdl 0 want the MDL-V1-REBUILD warning, got:\n%s", h.out.String()) + } + if !strings.Contains(h.mustDescribe(t, valFeedback), "@position(-380, 200)") { + t.Error("under mdl 0 the rebuild did not write the move") + } +} + +func (h *harness) mustDescribe(t *testing.T, target string) string { + t.Helper() + out, err := h.describe(target) + if err != nil || strings.TrimSpace(out) == "" { + t.Fatalf("describe %s: %v (output %q)", target, err, out) + } + return out +} + +// flowUnit returns the raw bytes of the microflow or nanoflow named name. +func (h *harness) flowUnit(t *testing.T, name string) []byte { + t.Helper() + for _, b := range h.snapshot().units { + typ, n := typeAndName(b) + if n == name && (typ == "Microflows$Microflow" || typ == "Microflows$Nanoflow") { + return b + } + } + t.Fatalf("flow %s not found", name) + return nil +} + +// requireKept fails when an element of before is missing from after, or is +// no longer the same element type. except names the action $Type of the one +// activity a replace is expected to take out: that activity and everything +// in it may go, nothing else. +func requireKept(t *testing.T, before, after []byte, except string) { + t.Helper() + a := elementIDs(t, after) + b := elementIDsExcept(t, before, except) + if except != "" && len(b) == len(elementIDs(t, before)) { + t.Fatalf("no activity holds a %s — the fixture changed", except) + } + for id, typ := range b { + got, ok := a[id] + switch { + case ok && got == typ: + case ok: + t.Errorf("$ID %s was a %s and is now a %s", uuidOf([]byte(id)), typ, got) + default: + t.Errorf("the %s with $ID %s is gone", typ, uuidOf([]byte(id))) + } + } +} + +// elementIDs maps every element $ID in a unit to its $Type. +func elementIDs(t *testing.T, raw []byte) map[string]string { + return elementIDsExcept(t, raw, "") +} + +// elementIDsExcept is elementIDs without the activities whose action is a +// skipAction, and without anything they contain. +func elementIDsExcept(t *testing.T, raw []byte, skipAction string) map[string]string { + t.Helper() + var doc bson.D + if err := bson.Unmarshal(raw, &doc); err != nil { + t.Fatalf("decode unit: %v", err) + } + out := map[string]string{} + var walk func(v any) + walk = func(v any) { + switch x := v.(type) { + case bson.D: + if skipAction != "" { + for _, e := range x { + if act, ok := e.Value.(bson.D); ok && e.Key == "Action" { + for _, ae := range act { + if ae.Key == "$Type" && ae.Value == skipAction { + return + } + } + } + } + } + var id, typ string + for _, e := range x { + switch e.Key { + case "$ID": + if b, ok := e.Value.(bson.Binary); ok { + id = string(b.Data) + } + case "$Type": + typ, _ = e.Value.(string) + default: + walk(e.Value) + } + } + if id != "" { + out[id] = typ + } + case bson.A: + for _, el := range x { + walk(el) + } + } + } + walk(doc) + return out +} + +// requireKeptBut is requireKept for a replace of the one activity whose +// action is a skipAction and whose subtree contains text. +func requireKeptBut(t *testing.T, before, after []byte, skipAction, text string) { + t.Helper() + var doc bson.D + if err := bson.Unmarshal(before, &doc); err != nil { + t.Fatalf("decode unit: %v", err) + } + gone := map[string]bool{} + var walk func(v any, inside bool) + walk = func(v any, inside bool) { + switch x := v.(type) { + case bson.D: + if !inside { + for _, e := range x { + if act, ok := e.Value.(bson.D); ok && e.Key == "Action" { + raw, _ := bson.Marshal(act) + for _, ae := range act { + if ae.Key == "$Type" && ae.Value == skipAction && bytes.Contains(raw, []byte(text)) { + inside = true + } + } + } + } + } + for _, e := range x { + if b, ok := e.Value.(bson.Binary); ok && e.Key == "$ID" && inside { + gone[string(b.Data)] = true + } + walk(e.Value, inside) + } + case bson.A: + for _, el := range x { + walk(el, inside) + } + } + } + walk(doc, false) + if len(gone) == 0 { + t.Fatalf("no %s holds %q — the fixture changed", skipAction, text) + } + a := elementIDs(t, after) + for id, typ := range elementIDs(t, before) { + if gone[id] { + continue + } + if got, ok := a[id]; !ok || got != typ { + t.Errorf("the %s with $ID %s is gone or changed type (now %q)", typ, uuidOf([]byte(id)), got) + } + } +} + +func countType(t *testing.T, raw []byte, typ string) int { + t.Helper() + n := 0 + for _, got := range elementIDs(t, raw) { + if got == typ { + n++ + } + } + return n +} From e521e2478d206d41d799c0e88a82d94556954baa Mon Sep 17 00:00:00 2001 From: Ako Date: Sun, 27 Sep 2026 15:36:06 +0000 Subject: [PATCH 09/13] executor: read the stored flow as mdl 0 when diffing under mdl 1 (#747) create or modify re-parsed the stored flow's description under the script's header. describe writes mdl 0, so under `mdl 1;` a stored line break described as `\n` read as a backslash and an n; a script stating exactly that then matched, reported Unchanged and wrote nothing, although the value it states differs from the stored one. The stored side is now described and parsed as mdl 0 always; the AST holds values, so it compares with a declared side parsed under any version. correctAmbiguousRanges applies in every case. Tests that exercised mdl 1 on VAL_Feedback relied on the misreading and now use a flow without a backslash escape for their mdl 1 leg; TestPedAppListActivitiesUnderMdl1 asserts the mdl 1 description of a flow of list activities is Unchanged. Co-Authored-By: Claude Opus 5.5 --- mdl/executor/cmd_flow_modify.go | 51 +++++++------- mdl/roundtrip/flow_modify_test.go | 102 ++++++++++++++++++++++------ mdl/roundtrip/list_activity_test.go | 3 + 3 files changed, 110 insertions(+), 46 deletions(-) diff --git a/mdl/executor/cmd_flow_modify.go b/mdl/executor/cmd_flow_modify.go index 2fdf0c369..ad17d3c31 100644 --- a/mdl/executor/cmd_flow_modify.go +++ b/mdl/executor/cmd_flow_modify.go @@ -190,29 +190,31 @@ func reportUnchanged(ctx *ExecContext, what string) { fmt.Fprint(ctx.Output, line) } -// describedFlowStmt describes the stored flow and parses the description -// under the language version of the script being run, so both sides are read -// by the same rules. See correctAmbiguousRanges for the one stored state the -// description cannot state under mdl 0. +// describedFlowStmt describes the stored flow and parses the description as +// mdl 0, the language describe writes, whatever the script's own header: the +// AST holds values (a string literal's text, not its spelling), so the stored +// side read by the rules it was written in compares with a declared side read +// by the script's. Re-parsing the description under the script's header +// instead misreads it wherever the two versions spell a value differently — a +// stored line break described as `\n` would read as a backslash and an n under +// mdl 1, agree with a script stating exactly that, and let the change pass as +// Unchanged. See correctAmbiguousRanges for the one stored state mdl 0 cannot +// state at all. func describedFlowStmt(ctx *ExecContext, d *flowDecl, a *alterFlowContext) (ast.Statement, error) { var buf bytes.Buffer - prev := ctx.Output - ctx.Output = &buf + prevOut, prevVer := ctx.Output, ctx.LanguageVersion + ctx.Output, ctx.LanguageVersion = &buf, langver.V0 var err error if d.nanoflow { err = describeNanoflow(ctx, d.name) } else { err = describeMicroflow(ctx, d.name) } - ctx.Output = prev + ctx.Output, ctx.LanguageVersion = prevOut, prevVer if err != nil { return nil, err } - src := buf.String() - if v := ctx.LanguageVersion; v > langver.V0 { - src = v.String() + ";\n" + src - } - prog, errs := visitor.Build(src) + prog, errs := visitor.Build(buf.String()) if len(errs) > 0 { return nil, fmt.Errorf("the description does not parse: %v", errs[0]) } @@ -229,18 +231,12 @@ func describedFlowStmt(ctx *ExecContext, d *flowDecl, a *alterFlowContext) (ast. default: continue } - if !limitOneIsListUnder(ctx.LanguageVersion) { - correctAmbiguousRanges(st, a.mf.ObjectCollection) - } + correctAmbiguousRanges(st, a.mf.ObjectCollection) return st, nil } return nil, fmt.Errorf("the description has no create statement") } -// limitOneIsListUnder reports whether `limit 1` reads as a list of one under v -// (the visitor's MDL-V1-LIMIT1 change). -func limitOneIsListUnder(v langver.Version) bool { return v >= langver.V1 } - // correctAmbiguousRanges fixes the stored side where its mdl 0 description // says something other than what is stored. // @@ -526,13 +522,8 @@ func (pd *patchDiff) gap(ins []ast.MicroflowStatement, stored []ast.MicroflowSta return pd.statements(d.ElseBody, s.ElseBody) } if sameIgnoringLayout(ins[0], del[0]) { - p := statementAnnotations(del[0]) - where := "" - if p != nil && p.Position != nil { - where = fmt.Sprintf(" at (%d, %d)", p.Position.X, p.Position.Y) - } - return cannotSplice("the %s%s is moved or its connectors are redrawn; the splice places new nodes only and does not move stored ones", - statementKind(del[0]), where) + return cannotSplice("the %s is moved or its connectors are redrawn; the splice places new nodes only and does not move stored ones", + describeAt(del[0])) } } cands := make([]mfmutator.Candidate, len(del)) @@ -578,6 +569,14 @@ func sameIfShell(declared, stored ast.MicroflowStatement) (*ast.IfStmt, *ast.IfS return d, s, true } +// describeAt names a stored statement and where it is drawn, for a message. +func describeAt(st ast.MicroflowStatement) string { + if p := statementAnnotations(st); p != nil && p.Position != nil { + return fmt.Sprintf("%s at (%d, %d)", statementKind(st), p.Position.X, p.Position.Y) + } + return statementKind(st) +} + // keepStoredNotes prepares the declared statements that replace a stored one. // The splice keeps the stored activity's annotation notes and attaches them to // the replacement's first activity, so the declared statement must carry the diff --git a/mdl/roundtrip/flow_modify_test.go b/mdl/roundtrip/flow_modify_test.go index bae87bac1..8944bf587 100644 --- a/mdl/roundtrip/flow_modify_test.go +++ b/mdl/roundtrip/flow_modify_test.go @@ -17,7 +17,10 @@ import ( // Pro-authored (PedApp), because an mxcli-authored flow is laid out the way the // rebuild lays it out and cannot show what the rebuild loses. -const valFeedback = "microflow FeedbackModule.VAL_Feedback" +const ( + valFeedback = "microflow FeedbackModule.VAL_Feedback" + sendToServer = "microflow FeedbackModule.SUB_Feedback_SendToServer" +) // An unchanged describe -> create or modify writes nothing: the unit's bytes // are identical. The controls below prove the same pipeline does write when @@ -26,24 +29,70 @@ func TestFlowModify_UnchangedIsByteIdentical(t *testing.T) { h := newHarness(t) defer h.close() - described := h.mustDescribe(t, valFeedback) - before := h.flowUnit(t, "VAL_Feedback") - for _, header := range []string{"", "mdl 1;\n"} { - if err := h.exec(header + described); err != nil { - t.Fatalf("header %q: exec unchanged describe output: %v", header, err) + // VAL_Feedback stores a line break in a message, which mdl 1 has no + // spelling for (its description's `\n` is a backslash and an n there; see + // MDL1ReadsStoredStringsAsStored), so its mdl 1 leg uses a flow without + // one: SUB_Feedback_SendToServer, with merges and an error handler. + for _, c := range []struct{ header, target, name string }{ + {"", valFeedback, "VAL_Feedback"}, + {"", sendToServer, "SUB_Feedback_SendToServer"}, + {"mdl 1;\n", sendToServer, "SUB_Feedback_SendToServer"}, + } { + described := h.mustDescribe(t, c.target) + before := h.flowUnit(t, c.name) + if err := h.exec(c.header + described); err != nil { + t.Fatalf("%s, header %q: exec unchanged describe output: %v", c.name, c.header, err) } - if got := h.flowUnit(t, "VAL_Feedback"); !bytes.Equal(got, before) { - t.Fatalf("header %q: the unchanged definition rewrote the unit", header) + if got := h.flowUnit(t, c.name); !bytes.Equal(got, before) { + t.Fatalf("%s, header %q: the unchanged definition rewrote the unit", c.name, c.header) } if changed := h.orig.diff(h.snapshot()); len(changed) != 0 { - t.Fatalf("header %q: the unchanged definition wrote: %s", header, strings.Join(changed, "; ")) + t.Fatalf("%s, header %q: the unchanged definition wrote: %s", c.name, c.header, strings.Join(changed, "; ")) } - if !strings.Contains(h.out.String(), "Unchanged microflow: FeedbackModule.VAL_Feedback") { - t.Errorf("header %q: want an Unchanged report, got:\n%s", header, h.out.String()) + if want := "Unchanged microflow: FeedbackModule." + c.name; !strings.Contains(h.out.String(), want) { + t.Errorf("%s, header %q: want an Unchanged report, got:\n%s", c.name, c.header, h.out.String()) } } } +// Under mdl 1 a backslash in a string is an ordinary character, so the +// description's `'…characters\n'` (mdl 0 for a line break, which is what +// VAL_Feedback stores) states a backslash and an n. The stored side must be +// read as stored — not by re-parsing its mdl 0 description under the script's +// header — or the two misreadings agree, the statement reports Unchanged and +// the value the script states is silently not written. +func TestFlowModify_MDL1ReadsStoredStringsAsStored(t *testing.T) { + h := newHarness(t) + defer h.close() + + described := h.mustDescribe(t, valFeedback) + const mdl0 = "characters\\n';" + if !strings.Contains(described, mdl0) { + t.Fatalf("describe output has no %q — the fixture changed:\n%s", mdl0, described) + } + // Control: under mdl 0 the same text is the stored value. + if err := h.exec(described); err != nil { + t.Fatalf("mdl 0: %v", err) + } + if changed := h.orig.diff(h.snapshot()); len(changed) != 0 { + t.Fatalf("mdl 0: the unchanged definition wrote: %s", strings.Join(changed, "; ")) + } + + before := h.flowUnit(t, "VAL_Feedback") + if err := h.exec("mdl 1;\n" + described); err != nil { + t.Fatalf("mdl 1: %v", err) + } + if bytes.Equal(h.flowUnit(t, "VAL_Feedback"), before) { + t.Fatal("mdl 1: a string that states another value than the stored one wrote nothing") + } + if !strings.Contains(h.out.String(), "(spliced: 1 replaced)") { + t.Errorf("mdl 1: want the one statement replaced by a splice, got:\n%s", h.out.String()) + } + if again := h.mustDescribe(t, valFeedback); !strings.Contains(again, "characters\\\\n';") { + t.Errorf("mdl 1: want the backslash stored as written:\n%s", again) + } +} + // Control: an inserted statement is written, as a splice. Every element the // stored unit had keeps its $ID and stays in the unit — including the merges // describe cannot show and the rebuild deleted (#721 A) — and only the new @@ -174,11 +223,15 @@ func TestFlowModify_BranchEditIsSpliced(t *testing.T) { if edited == described { t.Fatalf("describe output has no %q:\n%s", old, described) } + // mdl 0 only: under mdl 1 this flow's description also restates its + // stored line break as a backslash and an n (MDL1ReadsStoredStringsAsStored + // covers a branch splice under mdl 1). before := h.flowUnit(t, "VAL_Feedback") - for _, header := range []string{"mdl 1;\n", ""} { - if err := h.exec(header + edited); err != nil { - t.Fatalf("header %q: exec edited definition: %v", header, err) - } + if err := h.exec(edited); err != nil { + t.Fatalf("exec edited definition: %v", err) + } + if !strings.Contains(h.out.String(), "(spliced: 1 replaced)") { + t.Errorf("want a splice report, got:\n%s", h.out.String()) } after := h.flowUnit(t, "VAL_Feedback") if bytes.Equal(after, before) { @@ -204,13 +257,15 @@ func TestFlowModify_UnspliceableChange(t *testing.T) { h := newHarness(t) defer h.close() - described := h.mustDescribe(t, valFeedback) - const old = "@position(-390, 200)" - edited := strings.Replace(described, old, "@position(-380, 200)", 1) + // mdl 1: refused, nothing written. (On SUB_Feedback_SendToServer, whose + // description means under mdl 1 what it means under mdl 0; see + // UnchangedIsByteIdentical.) + described := h.mustDescribe(t, sendToServer) + const oldV1 = "@position(-730, -50)" + edited := strings.Replace(described, oldV1, "@position(-720, -50)", 1) if edited == described { - t.Fatalf("describe output has no %q:\n%s", old, described) + t.Fatalf("describe output has no %q:\n%s", oldV1, described) } - err := h.exec("mdl 1;\n" + edited) if err == nil || !strings.Contains(err.Error(), "cannot be spliced") || !strings.Contains(err.Error(), "moved") { t.Fatalf("under mdl 1 want a refusal naming the move, got %v", err) @@ -219,6 +274,13 @@ func TestFlowModify_UnspliceableChange(t *testing.T) { t.Fatalf("the refused statement wrote: %s", strings.Join(changed, "; ")) } + // mdl 0: rebuilt, with the warning. + described = h.mustDescribe(t, valFeedback) + const old = "@position(-390, 200)" + edited = strings.Replace(described, old, "@position(-380, 200)", 1) + if edited == described { + t.Fatalf("describe output has no %q:\n%s", old, described) + } if err := h.exec(edited); err != nil { t.Fatalf("under mdl 0: %v", err) } diff --git a/mdl/roundtrip/list_activity_test.go b/mdl/roundtrip/list_activity_test.go index cb3b55fc2..c5477da30 100644 --- a/mdl/roundtrip/list_activity_test.go +++ b/mdl/roundtrip/list_activity_test.go @@ -73,6 +73,9 @@ func TestPedAppListActivitiesUnderMdl1(t *testing.T) { if err := h.exec("mdl 1;\n" + first); err != nil { t.Fatalf("exec the mdl 1 description: %v\n%s", err, first) } + if !strings.Contains(h.out.String(), "Unchanged microflow: MyFirstModule.ListActivities") { + t.Errorf("GetPut: the mdl 1 description of an unchanged flow must write nothing, got:\n%s", h.out.String()) + } if again := h.describeUnder("mdl 1;", listActivityTarget); again != first { t.Errorf("describe -> exec -> describe changed the microflow:\n%s", lineDiff(first, again)) } From c6b1f0e9296952856535b9f0190f184527b5c163 Mon Sep 17 00:00:00 2001 From: Ako Date: Sun, 27 Sep 2026 15:36:10 +0000 Subject: [PATCH 10/13] executor: refuse a change inside a loop body instead of replacing the loop (#747) A declared loop that differed from the stored one only inside its body became a replace of the whole loop: every node in it rebuilt with new element IDs, and merges describe cannot show dropped - the rebuild's loss, confined to the loop, and under mdl 1 without the refusal the design and the skills promise for it. It is now a change the splice cannot make: refused under mdl 1, the warned rebuild under mdl 0. A changed loop iteration is still a replace. Co-Authored-By: Claude Opus 5.5 --- mdl/executor/cmd_flow_modify.go | 33 ++++++++++++++++ mdl/roundtrip/flow_modify_test.go | 66 +++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) diff --git a/mdl/executor/cmd_flow_modify.go b/mdl/executor/cmd_flow_modify.go index ad17d3c31..eb8c89e0c 100644 --- a/mdl/executor/cmd_flow_modify.go +++ b/mdl/executor/cmd_flow_modify.go @@ -521,6 +521,14 @@ func (pd *patchDiff) gap(ins []ast.MicroflowStatement, stored []ast.MicroflowSta } return pd.statements(d.ElseBody, s.ElseBody) } + if sameLoopShell(ins[0], del[0]) { + // The splice does not edit inside a loop, and the engine would + // take this as a replace of the whole loop: every node in it + // rebuilt, renumbered and redrawn — the rebuild's loss, confined + // to the loop but no less silent. + return cannotSplice("the %s changes inside its body; the splice does not edit inside a loop, "+ + "and replacing the whole loop would rebuild every node it holds", describeAt(del[0])) + } if sameIgnoringLayout(ins[0], del[0]) { return cannotSplice("the %s is moved or its connectors are redrawn; the splice places new nodes only and does not move stored ones", describeAt(del[0])) @@ -569,6 +577,31 @@ func sameIfShell(declared, stored ast.MicroflowStatement) (*ast.IfStmt, *ast.IfS return d, s, true } +// sameLoopShell reports whether two statements are the same loop — the same +// kind and iteration — differing at most in its body and its geometry. (A loop +// moved as well as edited inside is still a change inside the loop.) +func sameLoopShell(declared, stored ast.MicroflowStatement) bool { + switch d := declared.(type) { + case *ast.LoopStmt: + s, ok := stored.(*ast.LoopStmt) + if !ok { + return false + } + dShell, sShell := *d, *s + dShell.Body, sShell.Body = nil, nil + return sameIgnoringLayout(&dShell, &sShell) + case *ast.WhileStmt: + s, ok := stored.(*ast.WhileStmt) + if !ok { + return false + } + dShell, sShell := *d, *s + dShell.Body, sShell.Body = nil, nil + return sameIgnoringLayout(&dShell, &sShell) + } + return false +} + // describeAt names a stored statement and where it is drawn, for a message. func describeAt(st ast.MicroflowStatement) string { if p := statementAnnotations(st); p != nil && p.Position != nil { diff --git a/mdl/roundtrip/flow_modify_test.go b/mdl/roundtrip/flow_modify_test.go index 8944bf587..d80fd6881 100644 --- a/mdl/roundtrip/flow_modify_test.go +++ b/mdl/roundtrip/flow_modify_test.go @@ -292,6 +292,72 @@ func TestFlowModify_UnspliceableChange(t *testing.T) { } } +// A change inside a loop body is not a splice: the engine does not edit +// inside a loop, and replacing the whole loop would renumber and redraw every +// node it holds — the rebuild's loss, confined to the loop but just as silent. +// So under mdl 1 it is refused, and under mdl 0 it takes the warned rebuild. +// Control: a change after the loop in the same flow is spliced. +func TestFlowModify_LoopBodyChangeIsNotSpliced(t *testing.T) { + h := newHarness(t) + defer h.close() + + // PedApp has no loop, so this flow is mxcli-authored; the test is about + // what is refused, not about identity. + const create = `create microflow MyFirstModule.LoopFlow ( + $Items: List of FeedbackModule.Feedback +) +returns Integer +begin + declare $N Integer = 0; + loop $It in $Items begin + if $It/Subject != empty then + set $N = $N + 1; + end if; + log info node 'X' 'in loop'; + end loop; + log info node 'X' 'after loop'; + return $N; +end;` + if err := h.exec(create); err != nil { + t.Fatalf("create: %v", err) + } + const target = "microflow MyFirstModule.LoopFlow" + described := h.mustDescribe(t, target) + inLoop := strings.Replace(described, "'in loop'", "'in the loop'", 1) + if inLoop == described { + t.Fatalf("describe output has no 'in loop':\n%s", described) + } + before := h.flowUnit(t, "LoopFlow") + + err := h.exec("mdl 1;\n" + inLoop) + if err == nil || !strings.Contains(err.Error(), "cannot be spliced") || !strings.Contains(err.Error(), "loop") { + t.Fatalf("under mdl 1 want a refusal naming the loop, got %v", err) + } + if !bytes.Equal(h.flowUnit(t, "LoopFlow"), before) { + t.Fatal("the refused statement wrote") + } + + if err := h.exec(inLoop); err != nil { + t.Fatalf("under mdl 0: %v", err) + } + if !strings.Contains(h.out.String(), "Warning [MDL-V1-REBUILD]") { + t.Errorf("under mdl 0 want the MDL-V1-REBUILD warning, got:\n%s", h.out.String()) + } + if !strings.Contains(h.mustDescribe(t, target), "'in the loop'") { + t.Error("under mdl 0 the rebuild did not write the change") + } + + // Control: after the loop, the same kind of change is spliced. + described = h.mustDescribe(t, target) + after := strings.Replace(described, "'after loop'", "'after the loop'", 1) + if err := h.exec("mdl 1;\n" + after); err != nil { + t.Fatalf("control under mdl 1: %v", err) + } + if !strings.Contains(h.out.String(), "(spliced: 1 replaced)") { + t.Errorf("control: want a splice, got:\n%s", h.out.String()) + } +} + func (h *harness) mustDescribe(t *testing.T, target string) string { t.Helper() out, err := h.describe(target) From 9034b8ec8cac617ae979be36d1600b3a405b44b9 Mon Sep 17 00:00:00 2001 From: Ako Date: Sun, 27 Sep 2026 16:10:41 +0000 Subject: [PATCH 11/13] skills: condense write-microflows' Studio Pro guidance to stay within the 700-line skill budget Co-Authored-By: Claude Opus 5.5 --- .claude/skills/mendix/write-microflows/SKILL.md | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/.claude/skills/mendix/write-microflows/SKILL.md b/.claude/skills/mendix/write-microflows/SKILL.md index 4f05786ab..2b31169d5 100644 --- a/.claude/skills/mendix/write-microflows/SKILL.md +++ b/.claude/skills/mendix/write-microflows/SKILL.md @@ -44,14 +44,10 @@ Choose the mode by who owns the microflow ([choose-edit-mode](../choose-edit-mod (or fresh `describe` output) and re-run `create or modify`. - **Authored in Studio Pro:** prefer `alter microflow X { insert/replace/drop … }` (targets from `describe microflow X with handles`). `create or modify` of `describe` - output also works as a patch: an unchanged definition writes nothing, and an inserted, - replaced or dropped statement (at the top level or in an `if` branch) is spliced in, - leaving every other node, merge and curve as stored. A change it cannot splice — the - header, anything inside a loop body or error handler, a moved node — rebuilds the - whole microflow under mdl 0 - (warning `MDL-V1-REBUILD`: element IDs renumbered, merges removed, curves reset) and - is refused under `mdl 1;` (header and loop-body changes have no splice yet; move - nodes in Studio Pro). + output patches too: unchanged writes nothing; a top-level or `if`-branch statement + change is spliced in. Other changes (header, loop body, error handler, moved node) + rebuild the flow under mdl 0 (`MDL-V1-REBUILD`: IDs renumbered, merges and curves + lost) and are refused under `mdl 1;`. ## When to Use a Microflow vs a Nanoflow From 12bef67e3c4bac24276946953bf3e9cdfe44899e Mon Sep 17 00:00:00 2001 From: Ako Date: Sun, 27 Sep 2026 16:46:17 +0000 Subject: [PATCH 12/13] roundtrip: strike the 259 TestApp microflow entries #747's diff-then-patch fixes Co-Authored-By: Claude Opus 5.5 --- mdl/roundtrip/testapp_allowlist_test.go | 1007 +++++++++-------------- 1 file changed, 374 insertions(+), 633 deletions(-) diff --git a/mdl/roundtrip/testapp_allowlist_test.go b/mdl/roundtrip/testapp_allowlist_test.go index ad3778331..37fd30109 100644 --- a/mdl/roundtrip/testapp_allowlist_test.go +++ b/mdl/roundtrip/testapp_allowlist_test.go @@ -14,639 +14,380 @@ package roundtrip // rewrites are measured by TestTestAppCreateOrModifyProbe. Everything else is // the #721 classes on a larger fixture and has not been triaged per document. var testAppKnownFailures = map[string]knownFailure{ - "association Administration.AccountPasswordData_Account": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association Clients.Customer_Order": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association Clients.OrderLine_Order": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association Clients.Order_GetCustomerOrdersResponse": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association Clients.Order_SaveOrder": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association Clients.Product_OrderLine": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association Mappings.OrderLine_Order": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association Mappings.OrderLine_Product": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association Mappings.Order_Customer": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association Rules.BusinessRule_RuleCategory": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association Rules.RuleAction_BusinessRule": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association Rules.RuleExecutionLog_BusinessRule": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association ViewAssociations.persistent_order": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.CleanupHelper_WorkflowDefinition": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.ConflictReasonGroup_Workflow": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.ConflictReasonGroup_WorkflowDefinition": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.ConflictedWorkflowDefinitionView_WorkflowDefinition": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.ConflictedWorkflowHelper_Workflow": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.ConflictedWorkflowView_ConflictReasonGroup": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.ConflictedWorkflowView_CurrentActivitiesGroup": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.ConflictedWorkflowView_ExecutionPathGroup": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.ConflictedWorkflowView_Workflow": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.ConflictedWorkflowView_WorkflowDefinition": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.CurrentActivitiesGroup_Workflow": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.CurrentActivitiesGroup_WorkflowDefinition": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.DashboardContext_DefinitionHelperTask": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.DashboardContext_DefinitionHelperWorkflow": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.DashboardContext_Session": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.DashboardContext_TaskSummary": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.DashboardContext_WorkflowDefinition": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.DashboardContext_WorkflowSummary": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.DashboardContext_WorkflowTaskDefinition": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.DefinitionHelper_DashboardContext": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.DefinitionHelper_DefinitionHelperParent": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.ExecutionPathGroup_Workflow": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.ExecutionPathGroup_WorkflowDefinition": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.MyInitiatedWorkflowView_Initiator": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.MyInitiatedWorkflowView_ParentWorkflow": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.MyInitiatedWorkflowView_Workflow": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.TaskAssignmentHelper_User": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.TaskAssignmentHelper_WorkflowUserTask": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.TaskSeries_DashboardContext": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.TimelineViewer_Workflow": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.UserTaskOutcomeView_User": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.UserTaskOutcomeView_UserTaskView": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.UserTaskOutcomeView_WorkflowUserTaskOutcome": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.UserTaskView_Assignees": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.UserTaskView_TargetUsers": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.UserTaskView_WorkflowEndedUserTask": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.UserTaskView_WorkflowUserTask": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.UserTaskView_WorkflowUserTaskDefinition": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.UserTaskView_WorkflowView": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.WorkflowAttachment_WorkflowComment": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.WorkflowAuditTrailRecord_Workflow": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.WorkflowAuditTrailRecord_WorkflowDefinition": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.WorkflowCommentHelper_WorkflowComment": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.WorkflowComment_Workflow": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.WorkflowDefinitionHelper_WorkflowDefinition": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.WorkflowGroupHelper_WorkflowGroup": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.WorkflowGroupView_WorkflowGroup": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.WorkflowSeries_DashboardContext": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.WorkflowSummary_WorkflowDefinition": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.WorkflowTaskDetail_DashboardContext": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.WorkflowUserTaskView_Workflow": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.WorkflowUserTaskView_WorkflowEndedUserTask": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.WorkflowUserTaskView_WorkflowSubProcess": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.WorkflowUserTaskView_WorkflowUserTask": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.WorkflowUserTaskView_WorkflowUserTaskDefinition": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.WorkflowView_Initiator": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.WorkflowView_Workflow": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "association WorkflowCommons.WorkflowView_WorkflowDefinition": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.Alert": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.AlertIcon": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.AlertIcon_WithAction": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.Alert_WithAction": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.Breadcrumb": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.Breadcrumb_Underline": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.Card": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.Card_Action": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.Card_ActionWithImage": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.Card_Background": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.Card_WithImage": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.Form_Horizontal": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.Form_Horizontal_WithAction": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.Form_Horizontal_WithTitle": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.Form_Vertical": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.Form_Vertical_WithAction": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.Form_Vertical_WithTitle": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.Heroheader": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.Heroheader_Background": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.Heroheader_WithAction": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.ListItem_DoubleLine": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.ListItem_SingleLine": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.ListItem_WithImage": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.List_Cards": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.List_WithImage": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.Master_Detail": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.Pageheader": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.PageheaderImage": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.PageheaderImage_WithBack": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.PageheaderImage_WithControls": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.Pageheader_WithBack": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.Pageheader_WithControls": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.Pageheader_WithSearch": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.Timeline": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.Timeline_WithImage": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.Wizard_Arrow": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.Wizard_Arrow_Step": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.Wizard_Circle": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block Atlas_Web_Content.Wizard_Circle_Step": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "building block FeedbackModule.FeedbackWidget": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity Administration.Account": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity Administration.AccountPasswordData": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity Atlas_Web_Content.LoginContext": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity Clients.Customer": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity Clients.GetCustomerOrdersResponse": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity Clients.Order": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity Clients.OrderLine": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity Clients.Orders": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity Clients.Product": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity Clients.Root": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity Clients.SaveOrder": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity FeedbackModule.Feedback": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity FeedbackModule.ResponseHelper": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity Mappings.Customer": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity Mappings.Item": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity Mappings.Order": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity Mappings.OrderLine": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity Mappings.Product": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity MyFirstModule.Car": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity MyFirstModule.VCar": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity NanoflowCommons.Geolocation": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity NanoflowCommons.Position": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity Odata.Devices": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity Pages.Vehicle": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity Rules.BusinessRule": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity Rules.RuleAction": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity Rules.RuleCategory": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity Rules.RuleExecutionLog": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity ViewAssociations.OrdersVE": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity WorkflowCommons.AssignmentHelper": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity WorkflowCommons.AuditTrailViewer": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity WorkflowCommons.CleanupHelper": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity WorkflowCommons.Configuration": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity WorkflowCommons.ConflictReasonGroup": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity WorkflowCommons.ConflictedWorkflowDefinitionView": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "entity: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity WorkflowCommons.ConflictedWorkflowHelper": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity WorkflowCommons.ConflictedWorkflowView": {laws: []law{lawExec}, issue: "#721", why: "entity: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity WorkflowCommons.CurrentActivitiesGroup": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity WorkflowCommons.DashboardContext": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity WorkflowCommons.DefinitionHelper": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity WorkflowCommons.DurationHelper": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity WorkflowCommons.ExecutionPathGroup": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity WorkflowCommons.MyInitiatedWorkflowView": {laws: []law{lawExec}, issue: "#721", why: "entity: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity WorkflowCommons.NotificationArea": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity WorkflowCommons.TaskAssignmentHelper": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity WorkflowCommons.TaskCount": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity WorkflowCommons.TaskSeries": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity WorkflowCommons.TaskSummary": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity WorkflowCommons.TimelineViewer": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity WorkflowCommons.UserTaskOutcomeView": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity WorkflowCommons.UserTaskTimeLine": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity WorkflowCommons.UserTaskView": {laws: []law{lawExec}, issue: "#721", why: "entity: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity WorkflowCommons.WorkflowAttachment": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "entity: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity WorkflowCommons.WorkflowAuditTrailRecord": {laws: []law{lawExec}, issue: "#721", why: "entity: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity WorkflowCommons.WorkflowComment": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "entity: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity WorkflowCommons.WorkflowCommentHelper": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity WorkflowCommons.WorkflowDefinitionHelper": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity WorkflowCommons.WorkflowGroupHelper": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity WorkflowCommons.WorkflowGroupView": {laws: []law{lawParse}, issue: "#721", why: "entity: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity WorkflowCommons.WorkflowSeries": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity WorkflowCommons.WorkflowSummary": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity WorkflowCommons.WorkflowTaskDetail": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity WorkflowCommons.WorkflowUserTaskView": {laws: []law{lawExec}, issue: "#721", why: "entity: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity WorkflowCommons.WorkflowView": {laws: []law{lawExec}, issue: "#721", why: "entity: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "entity workflow.workfow1context": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "enumeration WorkflowCommons.Enum_NotificationArea_RenderAs": {laws: []law{lawGetPut}, issue: "#721", why: "enumeration: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "export mapping Clients.SoapOrderExportMapping": {laws: []law{lawGetPut}, issue: "#721", why: "export mapping: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "export mapping Services.OrdersExportMapping": {laws: []law{lawGetPut}, issue: "#721", why: "export mapping: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "external entity Clients.Orders": {laws: []law{lawExec}, issue: "#743", why: "describe external entity prints a plain create, refused on the existing entity; its create or modify probe leaves only #721 B"}, - "external entity Odata.Devices": {laws: []law{lawExec}, issue: "#743", why: "describe external entity prints a plain create, refused on the existing entity; its create or modify probe leaves only #721 B"}, - "import mapping Clients.SoapCustomerOrdersImportMapping": {laws: []law{lawGetPut}, issue: "#721", why: "import mapping: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "import mapping Clients.SoapOrdersImportMapping": {laws: []law{lawGetPut}, issue: "#721", why: "import mapping: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "javascript action DataWidgets.Reset_All_Filters": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "javascript action DataWidgets.Reset_Filter": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "javascript action DataWidgets.Set_Filter": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "javascript action FeedbackModule.JS_GetFeedbackStorageObject": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "javascript action NanoflowCommons.DraftEmail": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "javascript action NanoflowCommons.FindObjectWithGUID": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "javascript action NanoflowCommons.Geocode": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "javascript action NanoflowCommons.GetCurrentLocation": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "javascript action NanoflowCommons.GetCurrentLocationMinimumAccuracy": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "javascript action NanoflowCommons.GetGuid": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "javascript action NanoflowCommons.GetObjectByGuid": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "javascript action NanoflowCommons.GetStorageItemObject": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "javascript action NanoflowCommons.GetStorageItemObjectList": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "javascript action NanoflowCommons.RefreshEntity": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "javascript action NanoflowCommons.RefreshObject": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "javascript action NanoflowCommons.ReverseGeocode": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "javascript action NanoflowCommons.SetStorageItemObject": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "javascript action NanoflowCommons.SetStorageItemObjectList": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "javascript action NanoflowCommons.SetStorageItemString": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "javascript action NanoflowCommons.Share": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "javascript action NanoflowCommons.ShowConfirmation": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "javascript action NanoflowCommons.ShowProgress": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "javascript action NanoflowCommons.SignIn": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "javascript action WebActions.TakePicture": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "menu Atlas_Core.Phone_Menu": {laws: []law{lawGetPut}, issue: "#721", why: "menu: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "menu Atlas_Core.Tablet_Menu": {laws: []law{lawGetPut}, issue: "#721", why: "menu: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow Administration.ChangeMyPassword": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow Administration.ChangePassword": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow Administration.ManageMyAccount": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow Administration.NewAccount": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow Administration.NewWebServiceAccount": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow Administration.SaveNewAccount": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow Administration.ShowMyPasswordForm": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow Administration.ShowPasswordForm": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow Clients.GetCustomerOrders": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow Clients.GetOdataCustomerOrders": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow Clients.GetOdataOrders": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow Clients.GetOrders": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow Clients.GetProductId": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow Clients.GetRestOrder": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow Clients.SaveODataOrder": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow Clients.SaveOrder": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow CommitActivity.CommitNoEventsWithRefresh": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow CommitActivity.DefaultCommit": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow FeedbackModule.ConvertBase64String": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow FeedbackModule.ConvertUUIDToURL": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow FeedbackModule.PopulateUserAttributes": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow FeedbackModule.SUB_Feedback_PostToAppInsights": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow FeedbackModule.SUB_Feedback_Sanitize": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow FeedbackModule.SUB_Feedback_SendToServer": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow FeedbackModule.VAL_Feedback": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow Mappings.ImportItems": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow Mappings.PostBinary": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow Mappings.PostCustomRequestTemplate": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow Mappings.PostCustomRequestTemplate_2": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow Mappings.PostExportMapping": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow Mappings.PostFormData": {laws: []law{lawExec}, issue: "#721", why: "microflow: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow Microflows.MicroflowReduce": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow Microflows.SplitMerge": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow MyFirstModule.MyFirstLogic": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow MyFirstModule.RetrieveExamples": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow MyFirstModule.ZzMxcliProbe_Boolean": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow MyFirstModule.ZzMxcliProbe_Entity": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow MyFirstModule.ZzMxcliProbe_List": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow MyFirstModule.ZzMxcliProbe_LoopSplit": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow MyFirstModule.ZzMxcliProbe_Trivial": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow Odata.UnboundedActionMF": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow Odata.UnboundedActionMF2": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow Rules.MicroflowUsingRule": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow Services.GetCustomerOrders": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow Services.GetOrder": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow Services.SaveOrder": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_Attachment_Create": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_Attachment_Download": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_Attachment_Save": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_Attachment_Save_Admin": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_Comment_Delete": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_ConflictedWorkflowDefinitionView_Show": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_ConflictedWorkflowHelper_ApplyJumpTo": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_ConflictedWorkflowHelper_Workflow_Abort": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_ConflictedWorkflowHelper_Workflow_Continue": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_ConflictedWorkflowHelper_Workflow_JumpTo": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_ConflictedWorkflowHelper_Workflow_Restart": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_ConflictedWorkflowView_ShowWorkflowAdminPage": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_DashboardContext_Refresh": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_MyInitiatedWorkflowView_WithdrawWorkflow": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_TaskAssignmentHelper_Reassign": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_TaskAssignmentHelper_Reassign_Show": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_TaskAssignmentHelper_Retarget": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_TaskAssignmentHelper_Retarget_Show": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_TaskAssignmentHelper_Unassign": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_TaskAssignmentHelper_Unassign_Show": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_TaskAssignment_Show": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_TaskCount_Update": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_UserTaskView_Migrate": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_UserTask_AssignToMe": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_UserTask_AssignToMe_UpdateTaskCount": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_UserTask_AssignToUser": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_UserTask_AssignToUsers": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_UserTask_ShowDefaultAdminPage": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_UserTask_Unassign": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_User_WorkflowGroups_Add": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_User_WorkflowGroups_Remove": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_WorkflowCommentHelper_Edit_Save": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_WorkflowCommentHelper_SaveNew": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_WorkflowCommentHelper_SaveNew_Admin": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_WorkflowComment_Edit": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_WorkflowComment_Withdraw": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_WorkflowDefinitionHelper_ShowLockPage": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_WorkflowDefinitionHelper_ShowUnlockPage": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_WorkflowDefinition_CleanUp_Execute": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_WorkflowDefinition_CleanUp_Open": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_WorkflowDefinition_CloseActionConfirmation": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_WorkflowDefinition_Delete": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_WorkflowDefinition_Lock": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_WorkflowDefinition_Unlock": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_WorkflowGroupView_WorkflowGroup_Edit": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_WorkflowGroup_Users_Add": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_WorkflowGroup_Users_Remove": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_WorkflowJumpToDetails_Apply": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_WorkflowSubProcess_ShowDefaultAdminPage": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_WorkflowSummary": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_WorkflowUserTaskView_ShowDefaultAdminPage": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_WorkflowUserTaskView_ShowUserTaskPage": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_WorkflowUserTask_Assign": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_WorkflowUserTask_Assignees_Add": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_WorkflowUserTask_Assignees_Remove": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_WorkflowUserTask_TargetGroups_Add": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_WorkflowUserTask_TargetGroups_Remove": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_WorkflowUserTask_TargetUsers_Add": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_WorkflowUserTask_TargetUsers_Remove": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_WorkflowUserTask_Unassign": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_Workflow_Abort": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_Workflow_CloseActionConfirmation": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_Workflow_Continue": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_Workflow_JumpTo": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_Workflow_OpenParentWorkflow": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_Workflow_Pause": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_Workflow_Restart": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_Workflow_Retry": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_Workflow_Retry_KeepTargetedUsers": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_Workflow_Retry_RerunUserTargeting": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_Workflow_ShowWorkflowAdminPage": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ACT_Workflow_Unpause": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.ASU_UserTaskView_Migrate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.DS_Configuration": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.DS_ConflictedWorkflowView_ShowActionOptions": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.DS_MyInitiatedWorkflowView_TimelineViewer": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.DS_TaskAssignmentHelper_Account": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.DS_TaskCount": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.DS_TaskCount_Admin": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.DS_TaskDashboard": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.DS_TaskSeries": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.DS_TimelineViewer_WorkflowActivityRecords_Full": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.DS_TimelineViewer_WorkflowActivityRecords_Tasks": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.DS_WorkflowCommentHelper_InitializeNew": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.DS_WorkflowCurrentActivity_Options": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.DS_WorkflowDashboard": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.DS_WorkflowDefinition_Overview": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.DS_WorkflowDefinition_SelectableImplementation": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.DS_WorkflowSeries": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.DS_WorkflowTaskDefinition_Selectable_Administrator": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.DS_WorkflowTaskDefinition_Selectable_UserImplementation": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.DS_WorkflowTaskDetail": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.DS_WorkflowTask_AssignedToUser_Timeline": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.DashboardContext_GetSelectedWorkflowDefinition": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.DashboardContext_GetSelectedWorkflowTaskDefinition": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.OCH_Assignee_Search": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.OCH_CleanupHelper_UpdateCount": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.OCH_DashboardContext_UpdateTaskDashboard": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.OCH_DashboardContext_UpdateWorkflowDashboard": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SE_WorkflowAuditTrailRecord_CleanUp": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_CleanupHelper_Execute": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_CleanupHelper_Validate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_Configuration_FindOrCreate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_ConflictReasonGroup_FindOrCreate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_ConflictedWorkflowDefinitionView_UpdateConflictGroups": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_CurrentActivitiesGroup_FindOrCreate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_DashboardContext_RetrieveOrCreate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_DashboardContext_UpdateSettings": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_DashboardContext_UpdateWorkflowDashboard": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_ExecutionPathGroup_FindOrCreate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_TaskAssignmentHelper_Reassign": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_TaskAssignmentHelper_Retarget": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_TaskAssignmentHelper_TaskCount": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_TaskAssignmentHelper_Unassign": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_TaskCount_Update": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_TaskDashboard_Update": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_TaskSeriesList_Delete": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_TaskSeries_CreateOrUpdate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_TaskSummary_CreateOrUpdate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_TaskSummary_RetrieveOrCreate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_UserTaskOutcome_AssignedToUser_Completed": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_UserTaskOutcome_AssignedToUser_InProgress": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_UserTaskViewMigration_Verify": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_UserTaskView_Migrate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_UserTaskView_MigrateToWorkflowEndedUserTask": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_UserTask_Assign": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_UserTask_Assignee_Add": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_UserTask_Assignee_Remove": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_UserTask_Assignees_Add": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_UserTask_Assignees_Remove": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_UserTask_AverageHandlingTime": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_UserTask_CountAlmostDue": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_UserTask_CountCompleted": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_UserTask_CountCompletedOnTime": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_UserTask_CountCompletedOverdue": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_UserTask_CountFailed": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_UserTask_CountInProgress": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_UserTask_CountOverdue": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_UserTask_TargetGroups_Add": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_UserTask_TargetGroups_Remove": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_UserTask_TargetUser_Add": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_UserTask_TargetUser_Remove": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_UserTask_TargetUsers_Add": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_UserTask_TargetUsers_Remove": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_WorkflowAuditTrailRecord_CleanUp": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_WorkflowAuditTrailRecord_DeleteByKey": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_WorkflowDashboard_Update": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_WorkflowDefinitionHelper_FindOrCreate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_WorkflowEvent_AuditTrail": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_WorkflowJumpToDetails_Validate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_WorkflowSeriesList_Delete": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_WorkflowSeries_CreateOrUpdate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_WorkflowSummary_CreateOrUpdate": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_WorkflowSummary_RetrieveOrCreate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_WorkflowTaskDetail_CreateOrUpdate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_WorkflowTaskDetail_Delete": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_WorkflowTaskTimeline_Completed": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_WorkflowTaskTimeline_InProgress": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_WorkflowTask_AverageHandlingTime": {laws: []law{lawParse}, issue: "#721", why: "microflow: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_Workflow_AverageHandlingTime": {laws: []law{lawParse}, issue: "#721", why: "microflow: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_Workflow_CleanUpConflictGroups": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_Workflow_CommentAttachment_Validate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_Workflow_CountAlmostDue": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_Workflow_CountCompleted": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_Workflow_CountCompletedOnTime": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_Workflow_CountCompletedOverdue": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_Workflow_CountInProgress": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_Workflow_CountOverdue": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_Workflow_CurrentUserHasAccess": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_Workflow_Retry": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_Workflow_ShowWorkflowAdminPage": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_Workflow_UpdateConflictGroups": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_Workflow_UpdateConflictReasonGroup": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_Workflow_UpdateConflictResolutionEntities": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_Workflow_UpdateCurrentActivitiesGroup": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.SUB_Workflow_UpdateExecutionPathGroup": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "microflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow WorkflowCommons.WFEH_WorkflowEvent_AuditTrail": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow workflow.InvokeAgent": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow workflow.UserTaskEventHandle": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "microflow workflow.WorkflowEventHandle": {laws: []law{lawGetPut}, issue: "#721", why: "microflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "nanoflow Atlas_Web_Content.ACT_Login": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "nanoflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "nanoflow Atlas_Web_Content.DS_LoginContext": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "nanoflow FeedbackModule.ACT_Feedback_ClearForm": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "nanoflow FeedbackModule.ACT_Feedback_ClearImage": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "nanoflow FeedbackModule.ACT_Feedback_TriggerScreenshotMode": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "nanoflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "nanoflow FeedbackModule.ACT_Feedback_UploadImage": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "nanoflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "nanoflow FeedbackModule.ACT_Open_Feedback_Modal": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "nanoflow FeedbackModule.ACT_SubmitFeedback": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "nanoflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "nanoflow FeedbackModule.DS_Feedback_Populate": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "nanoflow FeedbackModule.Get_And_Set_Feedback_NPE": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "nanoflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "nanoflow FeedbackModule.OCH_Feedback_SaveToLocalStorage": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "nanoflow FeedbackModule.SUB_Feedback_GetOrCreate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "nanoflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "nanoflow FeedbackModule.SUB_Feedback_ResetLocalStorage": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "nanoflow MyFirstModule.Nanoflow": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "nanoflow WorkflowCommons.ACT_AuditTrailViewer_All": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "nanoflow WorkflowCommons.ACT_AuditTrailViewer_Default": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "nanoflow WorkflowCommons.ACT_AuditTrailViewer_Minimal": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "nanoflow WorkflowCommons.ACT_ConflictedWorkflowDefinitionView_Refresh": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "nanoflow WorkflowCommons.ACT_DoNothing": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "nanoflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "nanoflow WorkflowCommons.ACT_TaskCount_Refresh": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "nanoflow WorkflowCommons.ACT_TimelineViewer_OpenSubWorkflow": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "nanoflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "nanoflow WorkflowCommons.ACT_TimelineViewer_OpenWorkflow": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "nanoflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "nanoflow WorkflowCommons.ACT_WorkflowAuditTrailRecord_ExportToExcel": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "nanoflow WorkflowCommons.ACT_WorkflowAuditTrailRecord_Refresh": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "nanoflow WorkflowCommons.ACT_WorkflowComment_Withdraw_Confirm": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "nanoflow WorkflowCommons.DS_AuditTrailViewer": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "nanoflow WorkflowCommons.DS_MyInitiatedWorkflowView_LoadNotificationArea": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "nanoflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "nanoflow WorkflowCommons.DS_WorkflowActivityRecord_ActivityDuration": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "nanoflow WorkflowCommons.DS_WorkflowTask_LoadNotificationArea": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "nanoflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "nanoflow WorkflowCommons.DS_WorkflowUserTask_AssigneeHelper": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "nanoflow WorkflowCommons.DS_Workflow_LoadNotificationArea": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "nanoflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "nanoflow WorkflowCommons.DS_Workflow_TimelineViewer": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "nanoflow WorkflowCommons.OCH_WorkflowCurrentActivity_Target": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "nanoflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "nanoflow WorkflowCommons.SUB_AuditTrailViewer_Default": {laws: []law{lawGetPut}, issue: "#721", why: "nanoflow: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "nanoflow WorkflowCommons.SUB_Duration_Calculate": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "nanoflow: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "odata client Clients.OrderODataClient": {laws: []law{lawExec}, issue: "#743", why: "plain create refused until the rewrite carries UseQuerySegment, catalog, proxy and microflow settings and the icon"}, - "odata client Odata.Bug1073": {laws: []law{lawExec}, issue: "#743", why: "plain create refused until the rewrite carries UseQuerySegment, catalog, proxy and microflow settings and the icon"}, - "page Administration.Account_Edit": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page Administration.Account_New": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page Administration.Account_Overview": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page Administration.ActiveSessions": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page Administration.ChangeMyPasswordForm": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page Administration.ChangePasswordForm": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page Administration.MyAccount": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page Administration.RuntimeInstances": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page Administration.ScheduledEvents": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page FeedbackModule.PopupFailure": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page FeedbackModule.PopupFailure_Logo": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page FeedbackModule.PopupSuccess": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page FeedbackModule.PopupSuccess_Logo": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page FeedbackModule.ShareFeedback": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page FeedbackModule.ShareFeedback_Logo": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page MyFirstModule.Home_Web": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page Pages.EditableLIstView": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page Pages.Vehicle_Overview": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page Rules.BusinessRule_NewEdit": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page Rules.BusinessRule_Overview": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "page: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page Rules.RuleAction_NewEdit": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page Rules.RuleAction_Overview": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "page: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page Rules.RuleCategory_NewEdit": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page Rules.RuleCategory_Overview": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "page: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.ConflictResolution": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "page: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.ConflictedActivitiesHelper_JumpTo_Options": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.ConflictedWorkflowDefinitionView": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "page: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.ConflictedWorkflowDefinitionView_ActionConfirmation": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.DefaultWorkflowAdmin": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.ManageTaskAssignments": {laws: []law{lawExec}, issue: "#721", why: "page: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.MyInitiatedWorkflowView_WithdrawConfirmation": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.MyInitiatedWorkflows": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.TaskAssignmentHelper_UserTask_Reassign": {laws: []law{lawExec}, issue: "#721", why: "page: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.TaskAssignmentHelper_UserTask_Reassign_TargetUserOptions": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.TaskAssignmentHelper_UserTask_Retarget": {laws: []law{lawExec}, issue: "#721", why: "page: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.TaskAssignmentHelper_UserTask_Retarget_TargetUserOptions": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.TaskAssignmentHelper_UserTask_Unassign_TargetUserOptions": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.TaskDashboard": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "page: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.TaskInbox": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "page: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.UserTask_Assign": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "page: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.UserTask_Target": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.UserTask_TargetGroups": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.User_WorkflowGroup_Select": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.WorkflowAdminCenter": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.WorkflowAttachment_New": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "page: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.WorkflowAttachment_View": {laws: []law{lawExec}, issue: "#721", why: "page: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.WorkflowAuditTrailRecord_Overview": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.WorkflowCommentHelper_Edit": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.WorkflowComment_Edit_Admin": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.WorkflowDefinition_CleanUp": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.WorkflowDefinition_CleanUp_Preview": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.WorkflowDefinition_Lock": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.WorkflowDefinition_Overview": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.WorkflowDefinition_Unlock": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.WorkflowDefinition_View": {laws: []law{lawExec}, issue: "#721", why: "page: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.WorkflowEndedUserTask": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.WorkflowGroup_Edit": {laws: []law{lawExec}, issue: "#721", why: "page: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.WorkflowGroup_Overview": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.WorkflowGroup_User_Select": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.WorkflowSubProcess_View": {laws: []law{lawExec}, issue: "#721", why: "page: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.WorkflowUserTaskView_View": {laws: []law{lawExec}, issue: "#721", why: "page: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.Workflow_Dashboard": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page WorkflowCommons.Workflow_JumpTo_Options": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page workflow.MultiUserTaskPage": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "page workflow.UserTaskPage": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "published rest service Services.OrdersRestApi": {laws: []law{lawGetPut}, issue: "#721", why: "published rest service: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "rest client Clients.OrdersRestClient": {laws: []law{lawParse}, issue: "#721", why: "rest client: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "rest client Mappings.RestClient": {laws: []law{lawParse}, issue: "#721", why: "rest client: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "rule Rules.Rule1": {laws: []law{lawGetPut}, issue: "#721", why: "rule: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "rule Rules.Rule2": {laws: []law{lawGetPut}, issue: "#721", why: "rule: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "scheduled event WorkflowCommons.SE_WorkflowAuditTrailRecord_CleanUp": {laws: []law{lawGetPut}, issue: "#721", why: "scheduled event: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet Administration.ReadMe": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet Atlas_Core.FeedbackWidget": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet Atlas_Core.LanguageSelectorWidget": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet Rules.Entity_Menu": {laws: []law{lawParse}, issue: "#721", why: "snippet: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Readme": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_Account_InactiveIndicator": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_Assignee_Search": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_AuditTrailViewer_Toolbar": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_DashboardContext_Timeline": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_MyInitiatedWorkflowView_ActivityTimelineOnly_Tasks": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_MyInitiatedWorkflowView_NotificationArea": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_MyInitiatedWorkflowView_State": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_MyInitiatedWorkflowView_StateCircleOnly": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_MyInitiatedWorkflowView_TaskTimeLineOnly": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_MyInitiatedWorkflowView_TaskTimeline_WithoutName": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_TaskAssignmentHelper_Assignee_Search": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_TaskAssignmentHelper_TargetUser_Search": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_TaskAssignment_UserTask_Assignees": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_TaskAssignment_UserTask_TargetUsers": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_TaskCount_RefreshBTN": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_TaskDashboard_Header": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_TaskDashboard_Numbers": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_TimelineViewer_Timeline_Full": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_TimelineViewer_Timeline_Tasks": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_UserTask_Assignees": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_UserTask_AttachmentAndComments": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_UserTask_Detail": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_UserTask_DueDate": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_UserTask_DueDate_Warning": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_UserTask_Header": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_UserTask_NameColumn": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_UserTask_NameColumnWithIcon": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_UserTask_NotificationArea": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_UserTask_State": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_UserTask_TargetGroups": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_UserTask_TargetUsers": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_UserTask_TaskTimeline": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_UserTask_UnassignedMessage": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_WorkflowActivityRecord_ActivityIcon": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_WorkflowActivityRecord_Details": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_WorkflowActivityRecord_Header": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_WorkflowActivityRecord_TaskDueDate": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_WorkflowActivityRecord_TaskDueDate_Warning": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_WorkflowActivity_Details_ActivityType": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_WorkflowAuditTrailRecord_Overview": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_WorkflowDashboard_Header": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_WorkflowDashboard_TaskNumbers": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_WorkflowDashboard_WorkflowNumbers": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_WorkflowDefinition_Actions": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_WorkflowDefinition_AuditTrail": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_WorkflowDefinition_Header": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_WorkflowEndedUserTask_Assignees": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_WorkflowEndedUserTask_Header": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_WorkflowEndedUserTask_State": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_WorkflowEndedUserTask_TargetGroups": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_WorkflowEndedUserTask_TargetUsers": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_WorkflowGroup_Overview": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_WorkflowJumpToDetails": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_WorkflowSubProcess_Details": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_WorkflowSubProcess_IncompatibleWarning": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_WorkflowSubProcess_State": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_WorkflowUserTaskView_Assignees": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_WorkflowUserTaskView_Details": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_WorkflowUserTaskView_DueDate": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_WorkflowUserTaskView_DueDate_Warning": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_WorkflowUserTaskView_IncompatibleWarning": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_WorkflowUserTaskView_NameColumn": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_WorkflowUserTaskView_NameColumnWithIcon": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_WorkflowUserTaskView_State": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_WorkflowUserTask_IncompatibleWarning": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_Workflow_ActivityTimeline": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_Workflow_ActivityTimelineOnly_Full": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_Workflow_ActivityTimelineOnly_Tasks": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_Workflow_AuditTrail": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_Workflow_CommentsAndAttachments": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_Workflow_CommentsAndAttachments_Admin": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_Workflow_Detail": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_Workflow_DueDate_Warning": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_Workflow_Header": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_Workflow_MoreActions": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_Workflow_NotificationArea": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_Workflow_State": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_Workflow_StateCircleOnly": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_Workflow_SubProcessDetails": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_Workflow_TaskDetails": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_Workflow_TaskTimeLineOnly": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_Workflow_TaskTimeline": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "snippet WorkflowCommons.Snip_Workflow_TaskTimeline_WithoutName": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, - "workflow workflow.Workflow1": {laws: []law{lawExec}, issue: "#743", why: "plain create refused until the rewrite carries event sub-processes, outcome flows and activity names"}, - "workflow workflow.Workflow1_2": {laws: []law{lawExec}, issue: "#743", why: "plain create refused until the rewrite carries event sub-processes, outcome flows and activity names"}, + "association Administration.AccountPasswordData_Account": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association Clients.Customer_Order": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association Clients.OrderLine_Order": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association Clients.Order_GetCustomerOrdersResponse": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association Clients.Order_SaveOrder": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association Clients.Product_OrderLine": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association Mappings.OrderLine_Order": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association Mappings.OrderLine_Product": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association Mappings.Order_Customer": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association Rules.BusinessRule_RuleCategory": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association Rules.RuleAction_BusinessRule": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association Rules.RuleExecutionLog_BusinessRule": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association ViewAssociations.persistent_order": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.CleanupHelper_WorkflowDefinition": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.ConflictReasonGroup_Workflow": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.ConflictReasonGroup_WorkflowDefinition": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.ConflictedWorkflowDefinitionView_WorkflowDefinition": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.ConflictedWorkflowHelper_Workflow": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.ConflictedWorkflowView_ConflictReasonGroup": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.ConflictedWorkflowView_CurrentActivitiesGroup": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.ConflictedWorkflowView_ExecutionPathGroup": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.ConflictedWorkflowView_Workflow": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.ConflictedWorkflowView_WorkflowDefinition": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.CurrentActivitiesGroup_Workflow": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.CurrentActivitiesGroup_WorkflowDefinition": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.DashboardContext_DefinitionHelperTask": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.DashboardContext_DefinitionHelperWorkflow": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.DashboardContext_Session": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.DashboardContext_TaskSummary": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.DashboardContext_WorkflowDefinition": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.DashboardContext_WorkflowSummary": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.DashboardContext_WorkflowTaskDefinition": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.DefinitionHelper_DashboardContext": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.DefinitionHelper_DefinitionHelperParent": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.ExecutionPathGroup_Workflow": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.ExecutionPathGroup_WorkflowDefinition": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.MyInitiatedWorkflowView_Initiator": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.MyInitiatedWorkflowView_ParentWorkflow": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.MyInitiatedWorkflowView_Workflow": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.TaskAssignmentHelper_User": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.TaskAssignmentHelper_WorkflowUserTask": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.TaskSeries_DashboardContext": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.TimelineViewer_Workflow": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.UserTaskOutcomeView_User": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.UserTaskOutcomeView_UserTaskView": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.UserTaskOutcomeView_WorkflowUserTaskOutcome": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.UserTaskView_Assignees": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.UserTaskView_TargetUsers": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.UserTaskView_WorkflowEndedUserTask": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.UserTaskView_WorkflowUserTask": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.UserTaskView_WorkflowUserTaskDefinition": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.UserTaskView_WorkflowView": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowAttachment_WorkflowComment": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowAuditTrailRecord_Workflow": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowAuditTrailRecord_WorkflowDefinition": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowCommentHelper_WorkflowComment": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowComment_Workflow": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowDefinitionHelper_WorkflowDefinition": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowGroupHelper_WorkflowGroup": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowGroupView_WorkflowGroup": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowSeries_DashboardContext": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowSummary_WorkflowDefinition": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowTaskDetail_DashboardContext": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowUserTaskView_Workflow": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowUserTaskView_WorkflowEndedUserTask": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowUserTaskView_WorkflowSubProcess": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowUserTaskView_WorkflowUserTask": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowUserTaskView_WorkflowUserTaskDefinition": {laws: []law{lawExec}, issue: "#721", why: "association: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowView_Initiator": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowView_Workflow": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "association WorkflowCommons.WorkflowView_WorkflowDefinition": {laws: []law{lawGetPut}, issue: "#721", why: "association: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Alert": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.AlertIcon": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.AlertIcon_WithAction": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Alert_WithAction": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Breadcrumb": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Breadcrumb_Underline": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Card": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Card_Action": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Card_ActionWithImage": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Card_Background": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Card_WithImage": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Form_Horizontal": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Form_Horizontal_WithAction": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Form_Horizontal_WithTitle": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Form_Vertical": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Form_Vertical_WithAction": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Form_Vertical_WithTitle": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Heroheader": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Heroheader_Background": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Heroheader_WithAction": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.ListItem_DoubleLine": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.ListItem_SingleLine": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.ListItem_WithImage": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.List_Cards": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.List_WithImage": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Master_Detail": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Pageheader": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.PageheaderImage": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.PageheaderImage_WithBack": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.PageheaderImage_WithControls": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Pageheader_WithBack": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Pageheader_WithControls": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Pageheader_WithSearch": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Timeline": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Timeline_WithImage": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Wizard_Arrow": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Wizard_Arrow_Step": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Wizard_Circle": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block Atlas_Web_Content.Wizard_Circle_Step": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "building block FeedbackModule.FeedbackWidget": {laws: []law{lawParse}, issue: "#721", why: "building block: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Administration.Account": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Administration.AccountPasswordData": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Atlas_Web_Content.LoginContext": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Clients.Customer": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Clients.GetCustomerOrdersResponse": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Clients.Order": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Clients.OrderLine": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Clients.Orders": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Clients.Product": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Clients.Root": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Clients.SaveOrder": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity FeedbackModule.Feedback": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity FeedbackModule.ResponseHelper": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Mappings.Customer": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Mappings.Item": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Mappings.Order": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Mappings.OrderLine": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Mappings.Product": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity MyFirstModule.Car": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity MyFirstModule.VCar": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity NanoflowCommons.Geolocation": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity NanoflowCommons.Position": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Odata.Devices": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Pages.Vehicle": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Rules.BusinessRule": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Rules.RuleAction": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Rules.RuleCategory": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity Rules.RuleExecutionLog": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity ViewAssociations.OrdersVE": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.AssignmentHelper": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.AuditTrailViewer": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.CleanupHelper": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.Configuration": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.ConflictReasonGroup": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.ConflictedWorkflowDefinitionView": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "entity: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.ConflictedWorkflowHelper": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.ConflictedWorkflowView": {laws: []law{lawExec}, issue: "#721", why: "entity: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.CurrentActivitiesGroup": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.DashboardContext": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.DefinitionHelper": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.DurationHelper": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.ExecutionPathGroup": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.MyInitiatedWorkflowView": {laws: []law{lawExec}, issue: "#721", why: "entity: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.NotificationArea": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.TaskAssignmentHelper": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.TaskCount": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.TaskSeries": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.TaskSummary": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.TimelineViewer": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.UserTaskOutcomeView": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.UserTaskTimeLine": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.UserTaskView": {laws: []law{lawExec}, issue: "#721", why: "entity: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.WorkflowAttachment": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "entity: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.WorkflowAuditTrailRecord": {laws: []law{lawExec}, issue: "#721", why: "entity: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.WorkflowComment": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "entity: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.WorkflowCommentHelper": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.WorkflowDefinitionHelper": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.WorkflowGroupHelper": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.WorkflowGroupView": {laws: []law{lawParse}, issue: "#721", why: "entity: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.WorkflowSeries": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.WorkflowSummary": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.WorkflowTaskDetail": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.WorkflowUserTaskView": {laws: []law{lawExec}, issue: "#721", why: "entity: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity WorkflowCommons.WorkflowView": {laws: []law{lawExec}, issue: "#721", why: "entity: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "entity workflow.workfow1context": {laws: []law{lawGetPut}, issue: "#721", why: "entity: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "enumeration WorkflowCommons.Enum_NotificationArea_RenderAs": {laws: []law{lawGetPut}, issue: "#721", why: "enumeration: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "export mapping Clients.SoapOrderExportMapping": {laws: []law{lawGetPut}, issue: "#721", why: "export mapping: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "export mapping Services.OrdersExportMapping": {laws: []law{lawGetPut}, issue: "#721", why: "export mapping: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "external entity Clients.Orders": {laws: []law{lawExec}, issue: "#743", why: "describe external entity prints a plain create, refused on the existing entity; its create or modify probe leaves only #721 B"}, + "external entity Odata.Devices": {laws: []law{lawExec}, issue: "#743", why: "describe external entity prints a plain create, refused on the existing entity; its create or modify probe leaves only #721 B"}, + "import mapping Clients.SoapCustomerOrdersImportMapping": {laws: []law{lawGetPut}, issue: "#721", why: "import mapping: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "import mapping Clients.SoapOrdersImportMapping": {laws: []law{lawGetPut}, issue: "#721", why: "import mapping: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action DataWidgets.Reset_All_Filters": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action DataWidgets.Reset_Filter": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action DataWidgets.Set_Filter": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action FeedbackModule.JS_GetFeedbackStorageObject": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.DraftEmail": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.FindObjectWithGUID": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.Geocode": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.GetCurrentLocation": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.GetCurrentLocationMinimumAccuracy": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.GetGuid": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.GetObjectByGuid": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.GetStorageItemObject": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.GetStorageItemObjectList": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.RefreshEntity": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.RefreshObject": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.ReverseGeocode": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.SetStorageItemObject": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.SetStorageItemObjectList": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.SetStorageItemString": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.Share": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.ShowConfirmation": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.ShowProgress": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action NanoflowCommons.SignIn": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "javascript action WebActions.TakePicture": {laws: []law{lawParse}, issue: "#721", why: "javascript action: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "menu Atlas_Core.Phone_Menu": {laws: []law{lawGetPut}, issue: "#721", why: "menu: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "menu Atlas_Core.Tablet_Menu": {laws: []law{lawGetPut}, issue: "#721", why: "menu: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_WorkflowTask_AverageHandlingTime": {laws: []law{lawParse}, issue: "#721", why: "microflow: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "microflow WorkflowCommons.SUB_Workflow_AverageHandlingTime": {laws: []law{lawParse}, issue: "#721", why: "microflow: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "odata client Clients.OrderODataClient": {laws: []law{lawExec}, issue: "#743", why: "plain create refused until the rewrite carries UseQuerySegment, catalog, proxy and microflow settings and the icon"}, + "odata client Odata.Bug1073": {laws: []law{lawExec}, issue: "#743", why: "plain create refused until the rewrite carries UseQuerySegment, catalog, proxy and microflow settings and the icon"}, + "page Administration.Account_Edit": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page Administration.Account_New": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page Administration.Account_Overview": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page Administration.ActiveSessions": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page Administration.ChangeMyPasswordForm": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page Administration.ChangePasswordForm": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page Administration.MyAccount": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page Administration.RuntimeInstances": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page Administration.ScheduledEvents": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page FeedbackModule.PopupFailure": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page FeedbackModule.PopupFailure_Logo": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page FeedbackModule.PopupSuccess": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page FeedbackModule.PopupSuccess_Logo": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page FeedbackModule.ShareFeedback": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page FeedbackModule.ShareFeedback_Logo": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page MyFirstModule.Home_Web": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page Pages.EditableLIstView": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page Pages.Vehicle_Overview": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page Rules.BusinessRule_NewEdit": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page Rules.BusinessRule_Overview": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "page: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page Rules.RuleAction_NewEdit": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page Rules.RuleAction_Overview": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "page: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page Rules.RuleCategory_NewEdit": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page Rules.RuleCategory_Overview": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "page: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.ConflictResolution": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "page: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.ConflictedActivitiesHelper_JumpTo_Options": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.ConflictedWorkflowDefinitionView": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "page: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.ConflictedWorkflowDefinitionView_ActionConfirmation": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.DefaultWorkflowAdmin": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.ManageTaskAssignments": {laws: []law{lawExec}, issue: "#721", why: "page: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.MyInitiatedWorkflowView_WithdrawConfirmation": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.MyInitiatedWorkflows": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.TaskAssignmentHelper_UserTask_Reassign": {laws: []law{lawExec}, issue: "#721", why: "page: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.TaskAssignmentHelper_UserTask_Reassign_TargetUserOptions": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.TaskAssignmentHelper_UserTask_Retarget": {laws: []law{lawExec}, issue: "#721", why: "page: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.TaskAssignmentHelper_UserTask_Retarget_TargetUserOptions": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.TaskAssignmentHelper_UserTask_Unassign_TargetUserOptions": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.TaskDashboard": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "page: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.TaskInbox": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "page: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.UserTask_Assign": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "page: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.UserTask_Target": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.UserTask_TargetGroups": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.User_WorkflowGroup_Select": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.WorkflowAdminCenter": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.WorkflowAttachment_New": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "page: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.WorkflowAttachment_View": {laws: []law{lawExec}, issue: "#721", why: "page: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.WorkflowAuditTrailRecord_Overview": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.WorkflowCommentHelper_Edit": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.WorkflowComment_Edit_Admin": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.WorkflowDefinition_CleanUp": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.WorkflowDefinition_CleanUp_Preview": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.WorkflowDefinition_Lock": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.WorkflowDefinition_Overview": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.WorkflowDefinition_Unlock": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.WorkflowDefinition_View": {laws: []law{lawExec}, issue: "#721", why: "page: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.WorkflowEndedUserTask": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.WorkflowGroup_Edit": {laws: []law{lawExec}, issue: "#721", why: "page: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.WorkflowGroup_Overview": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.WorkflowGroup_User_Select": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.WorkflowSubProcess_View": {laws: []law{lawExec}, issue: "#721", why: "page: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.WorkflowUserTaskView_View": {laws: []law{lawExec}, issue: "#721", why: "page: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.Workflow_Dashboard": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page WorkflowCommons.Workflow_JumpTo_Options": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page workflow.MultiUserTaskPage": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "page workflow.UserTaskPage": {laws: []law{lawGetPut}, issue: "#721", why: "page: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "published rest service Services.OrdersRestApi": {laws: []law{lawGetPut}, issue: "#721", why: "published rest service: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "rest client Clients.OrdersRestClient": {laws: []law{lawParse}, issue: "#721", why: "rest client: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "rest client Mappings.RestClient": {laws: []law{lawParse}, issue: "#721", why: "rest client: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "rule Rules.Rule1": {laws: []law{lawGetPut}, issue: "#721", why: "rule: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "rule Rules.Rule2": {laws: []law{lawGetPut}, issue: "#721", why: "rule: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "scheduled event WorkflowCommons.SE_WorkflowAuditTrailRecord_CleanUp": {laws: []law{lawGetPut}, issue: "#721", why: "scheduled event: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet Administration.ReadMe": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet Atlas_Core.FeedbackWidget": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet Atlas_Core.LanguageSelectorWidget": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet Rules.Entity_Menu": {laws: []law{lawParse}, issue: "#721", why: "snippet: breaks parse on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Readme": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Account_InactiveIndicator": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Assignee_Search": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_AuditTrailViewer_Toolbar": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_DashboardContext_Timeline": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_MyInitiatedWorkflowView_ActivityTimelineOnly_Tasks": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_MyInitiatedWorkflowView_NotificationArea": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_MyInitiatedWorkflowView_State": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_MyInitiatedWorkflowView_StateCircleOnly": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_MyInitiatedWorkflowView_TaskTimeLineOnly": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_MyInitiatedWorkflowView_TaskTimeline_WithoutName": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_TaskAssignmentHelper_Assignee_Search": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_TaskAssignmentHelper_TargetUser_Search": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_TaskAssignment_UserTask_Assignees": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_TaskAssignment_UserTask_TargetUsers": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_TaskCount_RefreshBTN": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_TaskDashboard_Header": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_TaskDashboard_Numbers": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_TimelineViewer_Timeline_Full": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_TimelineViewer_Timeline_Tasks": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_UserTask_Assignees": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_UserTask_AttachmentAndComments": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_UserTask_Detail": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_UserTask_DueDate": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_UserTask_DueDate_Warning": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_UserTask_Header": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_UserTask_NameColumn": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_UserTask_NameColumnWithIcon": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_UserTask_NotificationArea": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_UserTask_State": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_UserTask_TargetGroups": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_UserTask_TargetUsers": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_UserTask_TaskTimeline": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_UserTask_UnassignedMessage": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowActivityRecord_ActivityIcon": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowActivityRecord_Details": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowActivityRecord_Header": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowActivityRecord_TaskDueDate": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowActivityRecord_TaskDueDate_Warning": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowActivity_Details_ActivityType": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowAuditTrailRecord_Overview": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowDashboard_Header": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowDashboard_TaskNumbers": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowDashboard_WorkflowNumbers": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowDefinition_Actions": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowDefinition_AuditTrail": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowDefinition_Header": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowEndedUserTask_Assignees": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowEndedUserTask_Header": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowEndedUserTask_State": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowEndedUserTask_TargetGroups": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowEndedUserTask_TargetUsers": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowGroup_Overview": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowJumpToDetails": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowSubProcess_Details": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowSubProcess_IncompatibleWarning": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowSubProcess_State": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowUserTaskView_Assignees": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowUserTaskView_Details": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowUserTaskView_DueDate": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowUserTaskView_DueDate_Warning": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowUserTaskView_IncompatibleWarning": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowUserTaskView_NameColumn": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowUserTaskView_NameColumnWithIcon": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowUserTaskView_State": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_WorkflowUserTask_IncompatibleWarning": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Workflow_ActivityTimeline": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Workflow_ActivityTimelineOnly_Full": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Workflow_ActivityTimelineOnly_Tasks": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Workflow_AuditTrail": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Workflow_CommentsAndAttachments": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Workflow_CommentsAndAttachments_Admin": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Workflow_Detail": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Workflow_DueDate_Warning": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Workflow_Header": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Workflow_MoreActions": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Workflow_NotificationArea": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Workflow_State": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Workflow_StateCircleOnly": {laws: []law{lawGetPut, lawPutGet}, issue: "#721", why: "snippet: breaks getput and putget on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Workflow_SubProcessDetails": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Workflow_TaskDetails": {laws: []law{lawGetPut}, issue: "#721", why: "snippet: breaks getput on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Workflow_TaskTimeLineOnly": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Workflow_TaskTimeline": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "snippet WorkflowCommons.Snip_Workflow_TaskTimeline_WithoutName": {laws: []law{lawExec}, issue: "#721", why: "snippet: breaks exec on TestApp, measured when it joined the harness (#743); not yet triaged into #721's classes"}, + "workflow workflow.Workflow1": {laws: []law{lawExec}, issue: "#743", why: "plain create refused until the rewrite carries event sub-processes, outcome flows and activity names"}, + "workflow workflow.Workflow1_2": {laws: []law{lawExec}, issue: "#743", why: "plain create refused until the rewrite carries event sub-processes, outcome flows and activity names"}, } // createOrModifyProbeKnownFailures is the allowlist of From 89bf9e175c2db9b62f58a5c1903467a59e7f1825 Mon Sep 17 00:00:00 2001 From: Ako Date: Sun, 27 Sep 2026 17:09:48 +0000 Subject: [PATCH 13/13] ci: check out the TestApp submodule in the roundtrip integration suite Co-Authored-By: Claude Opus 5.5 --- .github/workflows/push-test.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/push-test.yml b/.github/workflows/push-test.yml index a4b00ee72..1dc7a7e1b 100644 --- a/.github/workflows/push-test.yml +++ b/.github/workflows/push-test.yml @@ -221,9 +221,12 @@ jobs: - suite: other mxbuild: true steps: - # #743 adds TestApp as a git submodule to the round trip; its checkout - # will need `submodules: true` here for the roundtrip suite. - uses: actions/checkout@v7 + with: + # testdata/testapp (ako/TestApp), the round trip's second Studio + # Pro-authored fixture (#743); only the roundtrip suite reads it, and + # without it that test skips. + submodules: ${{ matrix.suite == 'roundtrip' }} - uses: actions/setup-go@v7 with: go-version: '1.26.6'