Skip to content

A package deploy's branchedDatabases is ignored at load, so the application runs on its base databases #3071

Description

@kriszyp

Problem

branchedDatabases on a root-config entry that also has package never takes effect. The application loads with no branches, and reads and writes the base databases it asked to fork. Every package and by_ref deploy writes such an entry. Together with deploy_component accepts branchedDatabases on a payload deploy and silently ignores it, this means no deploy request can give an application a fork on 5.3.0 or 5.3.1.

Nothing reports it. The deploy succeeds, no fork directory is created, and nothing is logged.

Cause

  • Branches are prepared only when loadComponent is called without an applicationScope (components/componentLoader.ts:865 at v5.3.0).
  • The root component's loop loads a package: entry with that entry's applicationScope and no branchedDatabases (:1000-1016).
  • Only the components-root directory loop passes rootConfigBranchedDatabases(appName) (:312, :363). An application with a package entry is evidently loaded by the root loop, since no fork directory appears.

The same code is at v5.3.1 and on main. The branched-database integration tests declare the key on an entry with no package (integrationTests/components/branched-database.test.ts:36), so this path is untested.

Reproduce (5.3.0)

An application with schema.graphql declaring type Item @table @export (default database data), packed with npm pack. Scratch install with http.securePort set and tls.unixDomainSockets: true.

  1. Deploy a base copy and write a row:
    harper deploy_component project=my-app package=/path/app-1.0.0.tgz restart=true
    curl -X PUT http://localhost:9926/Item/base-1 -d '{"name":"base"}' ...
  2. Deploy a second copy with a fork. isolated and host are there only to reach this copy apart from the base copy:
    harper deploy_component project=pkg-2 package=/path/app-1.0.0.tgz \
      isolated=true branchedDatabases='["data"]' host=pkg-2.example.test restart=true
    The root-config entry now has package, host, branchedDatabases: [data] and isolated: true.
  3. Write through the copy's own socket:
    curl --unix-socket '<rootPath>/sockets/app-pkg%2D2-<securePort>.sock' \
      -X PUT http://pkg-2.example.test/Item/pkg2-only -d '{"name":"pkg-2"}' ...
  4. GET /Item/ on the shared port returns pkg2-only: the write landed in the base. <rootPath>/database/`branches` has no pkg-2 directory.

The result is the same after a full harper stop / harper start, and with a local-path package (a symlink) instead of a tarball.

Contrast: payload-deploy the same application as pay-1, add host, isolated and branchedDatabases: [data] to its root-config entry by hand, and restart. The fork is created at <rootPath>/database/`branches`/pay-1/data, and writes through pay-1 stay out of the base.

Expected

An entry with package and branchedDatabases loads its application on its fork, the same as an entry without package. If the fork can't be created, the load fails, as it does today for an entry without package. It must never fall back to the base.

A regression test should deploy by package and check that a write through the application stays out of the base.

Context

Activity

  1. added this to the v5.4 milestone on Oct 6, 2026
  2. added theissue type on Oct 6, 2026
  3. self-assigned this
    on Oct 6, 2026
  4. kriszyp commented on Oct 7, 2026

    @kriszyp
    MemberAuthor

    The 5.3 docs record this as a known issue in Document isolated applications, branched databases, and threads.maxIsolated, along with manual steps for a payload-deployed app that have to be applied on every node. When this fix ships, those sentences need a fixed-in version. The PR's handoff names each place.

    — Claude Opus 5.5

  5. dawsontoth commented on Oct 7, 2026

    @dawsontoth
    Contributor

    @kriszyp looks like we've got two branches going, at first glance, it seems like yours is the real fix, mind is just a band-aid, right?

  6. dawsontoth commented on Oct 7, 2026

    @dawsontoth
    Contributor

    actually, seems like I'm wrong:

    Not quite. #3083 and #3066 fix two different bugs, and you need both.

    #3083 fixes package deploys (#3071). On a package deploy, branchedDatabases does get written to the app's root-config entry, but the package loader skipped preparing the branches, so the app ran on the base databases. #3083 only changes componentLoader.ts (plus tests and design notes), so that a package app gets its fork. For package deploys, that is the real fix.
    #3066 handles payload deploys (#3044). That's the default when you run harper deploy from a directory. A payload deploy writes no root-config entry, so deploy_component drops the value at deploy time and no loader ever sees it. #3083 doesn't touch that path. Its task brief says outright "Do not change the payload-deploy validation (harper#3066 owns it)", and its Related PRs line lists #3066 as independent.
    With #3083 alone, a payload deploy with branchedDatabases would still report success and run on the base databases.
    Honoring the field on payload deploys instead of refusing it is #3043. That would replace #3066's check. It's still open, with no milestone or assignee. It's a deploy-time change: the payload deploy would have to write host, urlPath, isolated and branchedDatabases to the root-config entry. The loader already honors that entry for directory apps; #3071's own contrast case shows the fork being created.

    The two PRs fit together: once #3083 lands, #3066's "use a package deploy" advice actually works. They don't share code, so merge order doesn't matter.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Fields

Priority

P1

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions