Preview Azure area and iteration moves with rule refusals and relation impact

Merged
UN
3d ago
+1115-5

Azure backlog moves previously required an agent to attempt a classification update to discover inherited permission denials or custom iteration rules. pm ado move-preview and the typed simulateMove SDK now return compact allowed/refused rows and direct relation scope evidence before any separate application request.

The command requires explicit linked pm IDs and one project/type. It reuses the shared project field contract, host SDK complete reads and renderer, existing batch reader, revision patch builder and same-organization relation mapper. All validation patches assert the observed revision and set validateOnly=true&bypassRules=false; no apply/save or implicit bulk-update path exists. Classification moves preserve links; relation output shows endpoint area/iteration boundaries in the scenario where all allowed rows move. Unreadable and opaque targets are explicit unknowns.

Before: moving Example\Old into Example\Release could discover an inherited deny or conditional process rule during application. After: each selected item reports allowed, permission_denied, process_rule, a stale revision or another typed refusal with a remedy, without saving changes.

AcceptanceEvidence
Deterministic inherited permissions and custom iteration rulesSynthetic REST project tests yield allowed/permission_denied/process_rule rows; reversing selection preserves the result; inherited source and destination denials are checked.
No implicit bulk updateExplicit 1..50 unique, scope-bound links; validation-only patches, no apply flag; remote and authoritative tracker snapshots unchanged.
Bounded requests and downstream relationsMaximum case: 50 rows, 200 direct links, exactly 56 requests. Relation fanout above the cap refuses; opaque/unreadable targets remain unknown.
Typed SDK, agent output and no gitPublic SDK types/refusals, installed JSON/TOON commands, README and SDK/CLI example; real SDK trackers with git absent from PATH and a ceiling directory.
Reuse rather than overlapCurrent CLI 2026.10.23 generic update and sibling Gantt scheduling have no Azure classification/ACL semantics. Reuses the shipped field-contract feature; no second crawler.

Validation:

  • npm run typecheck, npm run build, npm run build:test, npm run docstring (12 source files, 86 documented declarations), and git diff --check: pass. No standalone lint script is defined.
  • node --test --experimental-test-coverage --test-coverage-include=moves.ts test/moves.test.ts: 11/11 pass, zero skips; simulator 100% lines/branches/functions.
  • npx --no-install pm test pm-ado-move-simulator --run --progress: one linked command / 11 tests pass, zero skips.
  • Behavioral revert: changed only simulateMove to treat rejected validation responses as allowed. The permissions/rules regression failed with exit 1: the expected permission_denied and process_rule rows became allowed. Restored the function and reran the linked test successfully.
  • Full unchanged-threshold npm run release:check and bun run release:check: implementation CI passed both release gates and both Node 22/26 jobs. Each suite passed 226/226 with zero skips, in both native-coverage and statement-instrumented passes; 100/100/100/100 coverage across 8 measured source files, including 1,361/1,361 statements. Production audit: zero vulnerabilities. Final exact-head CI passed all four jobs at 463ae1a64905955aae5c1937cc9643d93a81a4fa with the same counts and coverage; this final commit only records the passing gates and releases the pm claim. The saturated host ran targeted checks only.

Real-data validation used a read-only, non-git export of the public unbraind/pm-ado tracker at 3592ce90e40331217021b053c479402642a23478. The SDK read 29 items, and all 63 authoritative files remained unchanged. The actual unlinked selection refused at zero remote requests. An explicitly synthetic Azure projection of those public identities, lifecycle states and relations produced 7 allowed rows, 6 inherited denials, 16 custom iteration-rule refusals, 8 direct relations with 5 boundary changes, 34 requests per preview and 11,057 JSON bytes. First preview: 62 ms; repeat with a git ceiling: 107 ms. Reversed-selection replay was identical; zero local or remote fixture mutations. This does not claim live Azure acceptance. Reproduction is documented in docs/move-simulator.md and test/real-data-moves.ts.

Limits: individual validation is not an atomic multi-item plan or a future authorization. Relation evidence covers direct classification boundaries, not transitive/team-board membership. Live Azure credentials were not used. No merge or release requested. Automated review skips/rate limits are missing review evidence; no human approval is claimed.

PM items:

Commits: b5112e3 (implementation and pm evidence), 463ae1a (CI receipt and claim release). pm-ado-move-simulator remains in progress and unclaimed for orchestrator verification; it was not closed.