Skip to content

test: record how TargetProcess answers a child's TeamIteration clear - #21

Merged
man8 merged 2 commits into
mainfrom
record-teamiteration-cascade-cassette
Sep 23, 2026
Merged

man8 merged 2 commits into
mainfrom
record-teamiteration-cascade-cassette

Conversation

@man8

@man8 man8 commented Sep 21, 2026 •

Copy link
Copy Markdown
Owner

What this records

A live recording of what TargetProcess does with a child's explicit
TeamIteration null while its parent is scheduled — the interaction no cassette
covered, and one the unit suite cannot answer: it drives a mock transport, so it
asserts what the client does with a discarded null, never whether TargetProcess
discards one.

A parent UserStory and a child Task, both in the same team and the same
sprint. The clear goes through clear_team_iteration, and TargetProcess
unsets the field
:

  • the write is POST /Task/<id> with body {"TeamIteration":null};
  • the verifying re-read comes back {"ResourceType": "Task", "Id": <id>, "TeamIteration": null} — the key present and null, so the library's "a
    field the re-read does not carry at all counts as cleared" lenience is not
    what passed it;
  • so clear_team_iteration returns the narrowed re-read rather than raising.

The test asserts exactly that, and nothing more.

What this does not establish

The cascade TeamIterationCascadeError guards against did not reproduce, in
either configuration the live run reached:

  1. a child created with no Team came back with no TeamIteration at all —
    TargetProcess holds a card's sprint through a team assignment, so there was
    nothing for a parent to cascade onto and nothing to clear;
  2. the child recorded here was given the sprint explicitly, so the value it
    cleared was one TargetProcess had stored against it.

The configuration left untested is a child that holds a team assignment but was
never given a sprint of its own — where a value shown against it could be the
parent's rather than its own, and a null would have nothing to unset. That is
the shape in which a cascade would be expected to bite, and it is the obvious
next thing to record.

The run also never re-read the parent after the child's clear, so the
cassette shows the parent scheduled before the clear and not after. Nothing in
the run writes to the parent in between.

TeamIterationCascadeError, SPEC.md and docs/USAGE.md are deliberately
untouched
. This adds an observation; whether that observation narrows the
documented behaviour is a design question, not one a fixture should settle on
its own.

Redaction

The cassette went through the existing record-time hooks in
tests/integration/conftest.py with no new scheme added, and the conventions
are those of the sibling write-path cassettes — placeholder host
example.tpondemand.com, Sanitised <Field> for every name and identity
field, entity Ids recorded as they came off the wire.

Verified over the committed file:

  • live hostname, bare tenant label, API token, a real access_token= value,
    any authorization header, any cookie header — zero hits each;
  • the only TP-shaped host present is example.tpondemand.com;
  • every Name / Login / FirstName / LastName / FullName in a response
    is the Sanitised <Field> placeholder. The two real strings are the entity
    names the test itself invented, on the request side, which is the documented
    rule for a write-path cassette;
  • the sandbox project Id is recorded as-is, per the convention CONTRIBUTING.md
    and .coderabbit.yaml both state — thirteen cassettes already on main
    carry it;
  • tests/test_cassette_guard.py returns clean on it, and was confirmed to
    actually read this file by planting a real Name in an in-memory copy and
    watching it flag Items[0].Team.Name.

Checks

  • pytest — 1506 passed (1505 before, plus this test)
  • the new test replays offline, no network, no credentials
  • ruff check, ruff format --check
  • scripts/check_internal_refs.py, check_large_files.py, check_todos.py
  • every pre-commit hook, including both commit-message guards
  • redaction grep over the new cassette, as above

Recording notes

Re-recording needs a team linked to the sandbox project for the duration of the
run, exactly as test_team_assignment_create_and_delete does — TargetProcess
will not put a card in a team's sprint unless that team is assigned to the
card's project. Every other run replays offline and needs no link. Every entity
the run created was deleted by it; the sandbox was swept afterwards and holds no
Task and no story of this module's prefix.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Added integration coverage for clearing a task’s team iteration when its parent story belongs to a scheduled iteration.
    • Verified that clearing the task’s iteration persists correctly and returns no remaining iteration or entity version data.
    • Added cleanup verification to ensure test-created stories and tasks are removed successfully.

A parent UserStory and a child Task in the same team and the same sprint, with
the child's explicit null sent through clear_team_iteration. TargetProcess
unsets the field: the verifying re-read carries "TeamIteration": null - the key
present and null, so the "a field the re-read does not carry counts as cleared"
lenience is not what passed it - and the method returns the re-read. Recorded
because no cassette covered it and the unit suite drives a mock transport, so
it can only assert what the client does with a discarded null, never whether
TargetProcess discards one.

The cascade the method guards against did not reproduce, in either of the two
configurations a live run reached. A child created with no Team came back with
no TeamIteration at all, so there was nothing to cascade onto; the child
recorded here was given the sprint explicitly, so the value it cleared was one
TargetProcess had stored for it. The case left untested is a child holding a
team assignment but never given a sprint of its own, where the value shown
against it could be the parent's rather than its own.

TeamIterationCascadeError and the prose describing it are deliberately
untouched. This records an observation; whether it narrows the documented
behaviour is not a question a fixture should settle on its own.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 21, 2026 •

Copy link
Copy Markdown

Review Change StackReview Change Stack

Understand this PR’s impact

Explore downstream dependencies and potential security impact with Blast Radius.

View blast radius →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: man8/targetprocess-py/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: d97c4901-9580-4508-ba00-0ca78161e4c2

📥 Commits

Reviewing files that changed from the base of the PR and between e867bda and f03b8f1.

📒 Files selected for processing (2)
  • tests/integration/cassettes/test_live_readwrite/test_clear_team_iteration_lands_on_a_child_of_a_scheduled_parent.yaml
  • tests/integration/test_live_readwrite.py

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The pull request adds an integration test and VCR cassette for clearing a child task’s TeamIteration when its parent user story remains in a scheduled iteration. The test verifies the cleared state and removes both created entities.

Changes

Team iteration clearing integration coverage

Layer / File(s) Summary
Scheduled iteration setup and entity creation
tests/integration/test_live_readwrite.py, tests/integration/cassettes/test_live_readwrite/...yaml
The test finds the sandbox project’s linked team and lowest-ID sprint. It creates a user story and child task in the scheduled iteration. Recorded interactions verify both assignments.
Child iteration clearing and cleanup
tests/integration/test_live_readwrite.py, tests/integration/cassettes/test_live_readwrite/...yaml
The test clears the child task’s TeamIteration and verifies that the re-read returns null without an EntityVersion. Cleanup deletes the task and user story, including when assertions fail.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Other

🚥 Pre-merge checks | ✅ 7
✅ Passed checks (7 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: recording TargetProcess behaviour when clearing a child task's TeamIteration. It is concise and follows the repository's Conventional Commits format.
Description check ✅ Passed The description is detailed and covers the change, observed behaviour, limitations, redaction, testing, and recording notes. It does not use the template headings or include the template's full checkl…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Docstring Coverage (Non-Test) ✅ Passed PASS. The authoritative pull-request diff contains only two files: a YAML cassette and tests/integration/test_live_readwrite.py. Both are test code and are excluded by the custom check. The only add…
Checklist Complete ✅ Passed The pull request description has eight gating task-list items under “Checks”. Each item is ticked with [x]. It has no unticked task-list item and no post-merge section that requires exclusion. Repos…
No Committed Superpowers Artefacts ✅ Passed The authoritative pull-request diff contains only one added file, under tests/integration/cassettes/, and one modified file, tests/integration/test_live_readwrite.py. The scoped diff for docs/superpow…
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
✨ Simplify code
  • Commit to this branch
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@man8

man8 commented Sep 21, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Sep 21, 2026 •

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@man8
man8 merged commit 7dda5b9 into main Sep 23, 2026
9 checks passed
@man8
man8 deleted the record-teamiteration-cascade-cassette branch September 23, 2026 14:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant