Skip to content

fix: flush whole-type multi-resource YAML deletions to disk on pull - #298

Merged
Ruari-Phipps merged 1 commit into
mainfrom
fix/multi-resource-yaml-cache-flush
Sep 1, 2026
Merged

fix: flush whole-type multi-resource YAML deletions to disk on pull#298
Ruari-Phipps merged 1 commit into
mainfrom
fix/multi-resource-yaml-cache-flush

Conversation

@Ruari-Phipps

Copy link
Copy Markdown
Collaborator

Summary

When an entire multi-resource YAML type is absent from the incoming projection, its
per-resource deletions were batched into the file cache and then discarded when the pull
returned — the pruned file never reached disk. Flush the cache after the whole-type
deletion pass, then clear it.

Motivation

The leftover cache entry was stamped with the file's pre-write mtime, so the staleness
check treated it as fresh and every later read in the same process saw a file state that
was not on disk. The visible symptom was a pull that had to be run twice before
poly diff came back clean. Split out of #288, but the bug is independent of auth
filtering — any pull that deletes an entire multi-resource type hits it.

Changes

  • Flush and clear the multi-resource YAML file cache after the whole-type deletion pass
    in _update_multi_resource_yaml_resources, so deletions reach disk and no stale cache
    entry survives the pull.
  • Regression test asserting the pruned file is written to disk and the cache is empty
    after the pull.

Test strategy

  • Added/updated unit tests
  • Manual CLI testing (poly <command>)
  • Tested against a live Agent Studio project
  • N/A (docs, config, or trivial change)

Checklist

  • ruff check . and ruff format --check . pass
  • pytest passes (1434 passed, 117 subtests)
  • No breaking changes to the poly CLI interface (or migration path documented)
  • Commit messages follow conventional commits

When an entire multi-resource YAML type is absent from the incoming
projection, its per-resource deletions were batched into the file cache
and then discarded when the pull returned - the pruned file never
reached disk. The leftover cache entry was also stamped with the file's
pre-write mtime, so the staleness check treated it as fresh and every
later read in the process saw a file state that was not on disk. The
visible symptom was a pull that had to be run twice before poly diff
came back clean.

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

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Coverage Report

Base (main) PR Change
76.5% 76.6% +0.0% ✅

Changed file coverage

File Coverage Change
poly/project.py 76.4% +0.0% ✅
poly/resources/resource.py 90.4% +0.6% ✅

@Ruari-Phipps
Ruari-Phipps merged commit 898f7cb into main Sep 1, 2026
6 checks passed
@Ruari-Phipps
Ruari-Phipps deleted the fix/multi-resource-yaml-cache-flush branch September 1, 2026 11:01
Ruari-Phipps added a commit that referenced this pull request Sep 1, 2026
…299)

## Summary

The API filters projections per permission slice: a user without read
access to a slice
gets a skeleton carrying only identity fields, with the substantive
fields stripped.
Every `from_projection` now detects an auth-filtered or absent slice and
drops that
resource type for the pull instead of crashing or building resources
from the skeleton.

First of two PRs replacing #288 (stacked on #298; the follow-up adds
slim reference
mappings so references to withheld resources still resolve to names).

## Motivation

Pulling as a restricted reader fails today. All 162 `pull failed` errors
on adk-service
in the last 30 days trace to auth-filtered slices:

- 116 × `KeyError` on `name` / `actions` / `description` — unguarded
field access on
  skeleton entities.
- 46 × `Duplicate resource file path found` / `File not found for
resource` — filtered
keyphrase-boosting and phrase-filter slices parsed with empty names,
collapsing every
  entry onto one file path.

## Changes

- Every `from_projection` guards its slice: an absent slice or one where
any entity is
missing a field the API always sends for readable data is treated as
withheld, logged
  at debug level, and yields no resources.
- Guards test field presence, never truthiness, so falsy-but-readable
values (empty
`content`, `active=False`) are not mistaken for filtered ones. Sentinel
fields are
chosen per slice where the obvious field is optional in the API schema
(e.g. variant
attributes guard on `type`, not `archived`; variants on `isDefault`, not
`name`).
- Functions check their three slices independently ("functions" gates
special and global
functions, "jupiter_flows" gates transition functions) — losing one
permission must not
  hide the others.
- New `slim_projection_test.py` with a skeleton-projection fixture built
from the fields
each slice always sends, asserting no registered resource type raises
and nothing
  half-built survives.

## Test strategy

- [x] Added/updated unit tests
- [ ] Manual CLI testing (`poly <command>`)
- [ ] Tested against a live Agent Studio project
- [ ] N/A (docs, config, or trivial change)

## Checklist

- [x] `ruff check .` and `ruff format --check .` pass
- [x] `pytest` passes (1443 passed, 153 subtests)
- [x] No breaking changes to the `poly` CLI interface (or migration path
documented)
- [x] Commit messages follow [conventional
commits](https://www.conventionalcommits.org/)

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

2 participants