T-U2JP-guard-cross-package-relative-reaches
State: open/ready · Impact: medium · Complexity: small
AUTO-DEFINED: this spec was best-effort machine-authored by /sdlc:task-auto-define on 2026-09-13 because the task is autonomy: autonomous/pr. Review the Goal, Approach, Today, Files-to-touch, and Acceptance-criteria carefully before trusting it.
A package git mv move recipe checks for the moved paths with a literal
string grep, but a live cross-package relative import (e.g.
resolve(__dirname, '../../other-package/x')) does not contain the moved
path as a substring, so it survives the grep and only fails at build/test
time. Make the move recipe (or a repo-wide guard) catch these.
Two live relative paths (tests/ui/mvux/vault-nodes.vaults.e2e.ts, experiences/fitness/tests/admin-registry.test.ts) resolved into the moved package by
..segments and were invisible to a path grep — a move recipe should grep forresolve(and../reaches into the moved directory, or the repo should ban cross-package relative reaches.— from T-4VNC-learning-p1-scaffold-solution’s post-mortem
| Location | Role today |
|---|---|
solutions/ontological/lib/model/entities/task/implementation-ready.md | Under “Files to touch”, the delete-row paragraph mandates enumerating files that reference a removed/moved path as modify rows, but says nothing about finding an indirect relative-path reach — only a literal-path grep is implied |
solutions/ontological/skills/task-define/SKILL.md | Step 4’s Today/Files-to-touch drafting bullet (“When the gap is in ## Today or ## Files to touch”) covers table shape and the five-form Location grammar, but has no reference-sweep methodology for delete rows |
solutions/ontological/skills/task-auto-define/SKILL.md | Step 5’s codebase-context bullet tells the synthesizer to confirm cited modify/delete paths exist, but says nothing about finding indirect reaches |
solutions/determined/experiences/fitness/tests/admin-registry.test.ts | Reads a sibling package’s generated file via new URL('../../../packages/vault-platform-client/src/generated/transport.ts', import.meta.url) — a live relative reach whose specifier never spells out solutions/determined/packages/vault-platform-client, so a literal grep for that path misses it |
solutions/determined/tests/ui/mvux/vault-nodes.vaults.e2e.ts | Reaches the same generated file via resolve(here, '..', '..', '..', 'packages/vault-platform-client/src/generated/transport.ts') — same gap, a resolve() call rather than a new URL() call |
Proposed
Section titled “Proposed”Extend the delete-row reference-enumeration paragraph in
implementation-ready.md with a second-grep mandate: alongside the
literal-path grep for the moved/removed path, the sweep must also
search for resolve( and new URL( call sites that contain a ..
path segment, then check whether each hit’s joined path lands inside
the directory being moved. task-define and task-auto-define gain a
matching one-line reminder at the point where they draft delete-row
touchpoints, pointing back at the contract so the mandate is
discoverable at the moment a sweep is run — the same
contract-plus-two-skill-mirrors shape
T-PSR1-reference-sweep-greps-unfiltered used for its
unfiltered-grep mandate (that task was superseded before it landed;
this task carries the shape through for this adjacent gap).
Approach
Section titled “Approach”- In
solutions/ontological/lib/model/entities/task/implementation-ready.md, extend the existingdelete-row enumeration sentence under “Files to touch” (the “also enumerate every file that references the removed path” paragraph). Add: the sweep must also grep forresolve(andnew URL(call sites that contain a..path segment, not rely on the literal-path grep alone — a relative-path reach built from separate segments can land inside the moved directory without the moved path ever appearing as a substring. State this as a parenthetical failure-pattern note, matching the style of the existing “(the recurring shape: …)” note already in that paragraph. - In
solutions/ontological/skills/task-define/SKILL.md, Step 4 (“Resolve gaps one at a time”), inside the## Today/## Files to touchdrafting bullet block, add one line: when a row isdelete, also grep forresolve(/new URL(call sites with a..segment when enumerating references, per the implementation-ready contract. - In
solutions/ontological/skills/task-auto-define/SKILL.md, Step 5 (“Synthesize gap fills”), inside the## Today/## Files to touchcodebase-context bullet, add the matching one-line reminder fordeleterows. - Keep the three edits consistent in wording — the rule is stated once, in the contract, and referenced (never restated) in the two skills.
| Area | Note |
|---|---|
solutions/ontological/lib/model/entities/task/implementation-ready.md | Extend the delete-row reference-enumeration paragraph under “Files to touch”: mandate a second grep for resolve(/new URL( call sites containing a .. segment, and name the generic failure pattern (a relative climb reaching the moved directory without the moved path appearing as a substring). |
solutions/ontological/skills/task-define/SKILL.md | In Step 4’s Today/Files-to-touch drafting bullet: add a one-line reminder that a delete row’s reference sweep must also grep for indirect relative reaches, pointing at the contract. |
solutions/ontological/skills/task-auto-define/SKILL.md | In Step 5’s codebase-context bullet: add the matching one-line reminder for delete-row reference enumeration. |
Acceptance criteria
Section titled “Acceptance criteria”- AC-1:
implementation-ready.md’sdelete-row paragraph (under “Files to touch”) states that the reference sweep must also check forresolve(ornew URL(call sites containing a..segment, not only a literal grep for the moved path. - AC-2: That same paragraph names the generic failure pattern: a relative-path reach built from separate segments can land inside the moved directory without the moved path ever appearing as a substring.
- AC-3:
solutions/ontological/skills/task-define/SKILL.mdcontains a one-line reminder, at its Today/Files-to-touch drafting guidance (Step 4), to also grep for indirect relative reaches when enumerating references for adeleterow, pointing back at the contract rather than restating the rule. - AC-4:
solutions/ontological/skills/task-auto-define/SKILL.mdcontains the matching one-line reminder at itsdelete-row codebase-context guidance (Step 5). - AC-5:
solutions/ontological/cli/sdlc entities validateagainst this file,docs/planning/tasks/T-U2JP-guard-cross-package-relative-reaches.md, exits 0.
Out of scope
Section titled “Out of scope”- Building an automated CI guard or script that runs the indirect-reach grep for the implementer. This task mandates the methodology in prose, the same route T-PSR1-reference-sweep-greps-unfiltered took for the unfiltered-grep mandate; mechanizing it is separate work if the manual sweep proves too easy to skip.
- Fixing the two existing relative reaches cited above
(
admin-registry.test.ts,vault-nodes.vaults.e2e.ts) — they remain as-is; migrating them off a relative climb is separate work. - Auditing the rest of the repo for other instances of the same pattern.
- Changing the five-form Location grammar or the Files-to-touch/Today
table shapes — only the
delete-row enumeration methodology changes.
Dependencies
Section titled “Dependencies”- none
Discovery context
Section titled “Discovery context”Spawned by /sdlc:spawn-task-pr on 2026-09-13 UTC from T-4VNC-learning-p1-scaffold-solution in git@github.com:sksizer/dev.git.