Day 90

Day 90 - July 30, 2026: Following the Dependency Graph to a Clean Security State

A Day 90 reflection on resolving automated dependency updates by tracing build failures, lockfile scope, transitive vulnerabilities, and tooling compatibility.

July 30 began with what looked like a queue of automated dependency updates.

It became an investigation of build compatibility, generated lockfiles, package-manager scope, transitive dependencies, and the order in which related pull requests needed to move.

I worked through security and dependency maintenance in Domain Placeholder Platform, Tech Talent Pulse, and Lingua Core Platform. Some Dependabot pull requests merged after ordinary review. Others needed their branches refreshed, became obsolete after another change landed, or exposed a repository problem that a version bump alone could not solve.

By the end of the day, the required builds and checks passed, the relevant audits reported no known vulnerabilities, obsolete automated pull requests were closed, and the repositories’ security dashboards reflected a clean state.

That result did not come from treating each notification as an isolated task. It came from following the dependency graph until the repository as a whole was healthy.

An Automated Pull Request Is A Starting Point

Dependabot is good at identifying that a dependency can move.

It cannot always know whether the proposed branch still reflects the latest base branch, whether another merged update has already replaced its work, or whether a repository’s build tools agree about the new dependency graph.

Domain Placeholder Platform provided the straightforward version of that lesson.

PR #64 merged and closed. PR #63 had previously been blocked by failing checks, but updating its branch with the latest main changed the evidence: the checks succeeded, and the pull request merged.

Dependabot then automatically closed PRs #65 and #66 because their proposed updates were no longer necessary.

No separate manual repair was required for those two pull requests. The repository had moved underneath them. Refreshing the dependency branches showed which changes were now valid and which changes had become redundant.

This was a useful reminder that a red automated pull request does not always mean its package needs a custom fix. Sometimes its branch is stale. Sometimes another merged change has already established the required version. Updating the proposal against the current base can resolve an outdated check or prove that no proposal remains to merge.

One Dependency Sequence Exposed Several Boundaries

Tech Talent Pulse was the main technical story of the day.

PR #36 was a straightforward Dependabot update. I reviewed and merged it, and the repository’s visible security-alert count fell from 17 to 8.

That was meaningful progress, but it was not the final state.

Dependabot PR #31 continued to fail its build and verification checks. PR #37 was created with Copilot assistance to address the remaining findings, but it did not fully resolve the repository. PR #38 then supplied an additional unblocking change and merged. After PR #31 was updated again, its checks finally passed. PR #39 ultimately contained the changes required to clear the remaining security issues.

The sequence matters.

No single pull request fixed everything. The successful result came from reviewing the state after each change, using the next failure as diagnostic information, and continuing until both application validation and security evidence were clean.

A Security Upgrade Met A JSON Compatibility Boundary

The Java build failure behind the dependency upgrade came from a real compatibility boundary.

Spring Boot 4.1 changed its default JSON stack to Jackson 3. The application still used Jackson 2 imports under com.fasterxml.jackson.*. The dependency upgrade therefore changed more than a version number: it changed an assumption below the application’s source code.

A focused compatibility dependency allowed the existing application to keep compiling without turning the security-maintenance task into an immediate, large Jackson 3 migration.

That was a practical bridge, not a claim about the ideal permanent architecture. Compatibility dependencies should remain visible and can be removed when the application completes the larger migration or when upstream support makes them unnecessary.

The backend validation command was:

mvn clean verify

There was also a smaller troubleshooting lesson inside that work. Maven first failed because I ran the command from the frontend directory, where there was no project pom.xml. Running the same command from the repository root resolved that problem.

The command itself had not changed.

Its context had.

A Clean Audit Was Looking At The Wrong Workspace

The remaining frontend findings were initially confusing.

These commands reported no changes and no known vulnerabilities:

pnpm --dir frontend install
pnpm --dir frontend audit

That looked reassuring, but it conflicted with the repository’s visible security state.

The discrepancy came from pnpm detecting an unrelated parent workspace outside the repository. The commands were not treating the frontend as the independent project I expected them to inspect. A successful command was therefore not enough evidence. I also needed to verify which workspace and lockfile the package manager was using.

Explicitly ignoring the unexpected parent workspace corrected the scope:

pnpm --dir frontend --ignore-workspace install --no-frozen-lockfile

The frontend lockfile could then be regenerated from the intended project state.

This was one of the day’s most reusable lessons. Tools can exit successfully while operating in a context different from the one a developer has in mind. A clean audit is only meaningful when it audits the dependency graph that will actually be installed.

Transitive Repairs Needed A Narrow Escape Hatch

Refreshing the lockfile removed much of the confusion, but a smaller set of transitive vulnerabilities remained.

Transitive packages are installed because another dependency needs them, so they may not appear as direct choices in the project’s manifest. Temporary pnpm overrides selected patched versions of:

Overrides are useful when the direct dependency chain has not yet selected a patched compatible release. They are also an exception that the repository now owns.

I treated these as focused, practical fixes rather than permanent ideal architecture. They should be revisited after the upstream dependency chain naturally includes the patched versions. Until then, the lockfile and audits provide evidence that the vulnerable resolutions are no longer installed.

After the changes, both the full audit and the production-only audit reported no known vulnerabilities.

Security Changes Also Test The Toolchain

The security upgrades exposed another compatibility boundary in the frontend.

TypeScript 7.0.2 was outside the supported peer range of the installed @astrojs/check version. As a result, astro check crashed while accessing the TypeScript configuration.

Pinning TypeScript to 5.9.3 restored compatibility with the Astro checking toolchain.

Again, the important outcome was not choosing the highest available version. It was choosing a secure, supported combination that left the project’s validation working. A dependency update that clears an audit while breaking the typechecker is not a complete maintenance result.

Final frontend validation included:

pnpm --dir frontend --ignore-workspace install --frozen-lockfile
pnpm --dir frontend --ignore-workspace check
pnpm --dir frontend --ignore-workspace build
pnpm --dir frontend --ignore-workspace audit
pnpm --dir frontend --ignore-workspace audit --prod

The frozen installation, frontend check, and production build passed. The full and production audits reported no known vulnerabilities.

A Generated Lockfile Blocked Valid Updates

Lingua Core Platform demonstrated a different source of repeated dependency failures.

Dependabot PRs #236, #237, and #238 were all failing for the same non-security reason: Prettier was attempting to format pnpm-lock.yaml.

The lockfile is generated dependency data. Applying a source formatter to it added noise and blocked otherwise valid updates without improving the quality of the source code.

PR #239 added the lockfile to .prettierignore. That small governance change removed the repeated friction while preserving meaningful formatting checks for the files the repository’s authors maintain directly.

Afterward, PR #236 was updated with the latest main and merged successfully. I added an @dependabot rebase comment to PR #237; after rebasing, Dependabot determined that the proposed change was already present. PR #238 was similarly refreshed and automatically closed because no update remained necessary.

Those closures were different from merges, and the distinction matters. The repository did not need three additional dependency changes. It needed an accurate view of which changes still existed after the base branch and generated lockfile policy were corrected.

An Empty Pull Request Queue Was Not A Clean Security State

Even after the pending dependency pull requests were resolved, Lingua Core Platform’s Security and quality tab still showed 16 alerts.

That was evidence that the pull request queue and the security state were two different views of the repository.

I copied the public alert titles into Codex and used them as the starting point for a repository dependency audit. Codex created a focused branch, inspected the dependency graph, and updated the problematic dependencies. I reviewed the result and merged it through a pull request.

The audit ran twice for a reason.

The first pass identified and corrected the problematic dependency state. The second pass verified the result. After the merge, the Security and quality tab showed no remaining flagged items.

That does not mean the repository can never receive another vulnerability. Advisories and dependency graphs continue to change. It means the audit and GitHub security dashboard were clean at the conclusion of July 30’s work.

Validate The Repository, Not The Notification

Across the three repositories, automated pull requests were valuable instruments.

They identified available updates, prepared focused diffs, and made dependency maintenance visible. Codex and Copilot also accelerated parts of the investigation and implementation.

None of those tools defined the final state by itself.

The repository was the unit that needed to become healthy. That required checking several connected forms of evidence:

This is why security maintenance is more than merging Dependabot pull requests.

A red check may point to stale branch state, a generated file in the wrong validation path, a framework migration boundary, or a package manager using an unexpected workspace. A green audit may be looking at the wrong lockfile. An empty automated-update queue may coexist with unresolved security alerts.

The individual notification is a clue.

The complete repository state is the outcome.

Outcome

Day 90 completed a multi-repository security and dependency-maintenance pass using only public repository work.

In Domain Placeholder Platform, PR #64 merged, the previously blocked PR #63 passed after being updated with the latest main, and Dependabot automatically closed PRs #65 and #66 after their proposed updates became unnecessary.

In Tech Talent Pulse, PR #36 provided the straightforward update and reduced the visible security alerts from 17 to 8. PR #31 and PRs #37 through #39 formed a connected troubleshooting sequence rather than one all-purpose fix. The work addressed the Spring Boot 4.1 and Jackson compatibility boundary, rebuilt the frontend lockfile in the correct pnpm scope, applied focused temporary overrides for remaining transitive findings, and restored Astro checking by pinning TypeScript to a supported version. PR #39 ultimately cleared the remaining security issues.

In Lingua Core Platform, PR #239 stopped Prettier from treating the generated pnpm lockfile as authored source. That unblocked the dependency sequence: PR #236 merged, while refreshed PRs #237 and #238 were automatically closed when their updates were no longer needed. A separate Codex-assisted dependency audit then addressed the 16 alerts that remained after the automated pull request queue was clear. A second audit and the GitHub dashboard confirmed the clean result.

At the conclusion of the day’s work, the required checks and builds passed, the relevant audits reported no known vulnerabilities, and the security dashboards showed no remaining flagged items. Those statements describe the verified state on July 30, not a guarantee about future advisories.

Definition Of Done

Day 90 reached the July 30 repository-security checkpoint: