fix(datastore): write gitlab_user_id on hosted maven and npm versions

Summary

Every hosted Maven and npm version serves created_by: null. The columns, the OpenAPI field, and the management-API serializer exist, but nothing writes gitlab_user_id on either table. The monolith's version list (S14) and sidebar (S06) render Source from it. The fix reads auth.IdentityFromContext(ctx).Subject.LocalID at the two publish handlers and binds it into the two version INSERTs.

gitlab_project_id and gitlab_git_commit_sha stay null. Today's token has no carrier: userauth.GitLabClaims has five fields, none CI-related, and ADR-021 collapses every credential type to the User principal. Writing them waits on an ADR-020 amendment and an IAM token-issuer change, both outside this repo.

What a reviewer should not have to infer:

  • First publish wins. The value rides the INSERT VALUES only and both ON CONFLICT arms are untouched, so the column names the request that created the version row. On Maven that row commits on the pool before the body streams, so an aborted first upload keeps its user. S10 Step 4c now states this as the contract.
  • The accessor bounds the value and never fails a publish. (*auth.Identity).GitLabUserID() returns nil for an anonymous identity, for a principal outside relationships.OriginOrganization (a bare federated id would collide with an organization one, and the column carries no origin), and for an empty, over-255-byte, NUL-bearing, or invalid-UTF-8 id. The CHECK is char_length <= 255, so a byte bound is strictly tighter for valid UTF-8. Invalid UTF-8 would otherwise fail the INSERT with SQLSTATE 22021.
  • Attribution is metered where the row is written. gitlab_artifact_registry_maven_versions_created_total and its npm twin book each created version row under attributed="true" or "false", Maven on the INSERT arm only and npm on every 201, and publisherFromContext logs a WARN and proceeds unattributed when the identity holder is missing. Under the bootstrap stub every row books false, which the two docs/dev/observability.md rows name as the expected reading.
  • FindOrCreateVersion gains a positional *string across 13 call sites. Its RETURNING still does not project the column, so the tests read it back through a separate query.
  • authtest.Anonymous is a second plain-equality validator for the bootstrap arm. The existing no-authtest-in-prod depguard rule keeps it out of production, and its desc now names both validators.

Size

1046 reviewable LOC across 40 files (git diff --numstat origin/main...HEAD at 17d140ad4), over the 500-LOC guardrail.

Group Files LOC
Test Go 22 768
Test-support Go without a build tag (internal/auth/authtest/fake.go) 1 65
Production Go 10 145
Docs (S10, S17, observability, two e2e catalogs) 5 42
.golangci.yaml 1 9
api/openapi/v1.yaml 1 17

Tests and test support are 833 of the 1046 (80%). The production delta is the accessor, two VALUES entries, two field declarations, two handler reads through publisherFromContext, one adapter pass-through, and the two versions_created_total collectors with their cardinality entries. Splitting tests from the fix breaks the test-first pairing, and splitting Maven from npm leaves the shared accessor's second caller unreached. Eight test files carry only the one-token call-site edit the positional parameter forces, and another changes one assertion message.

Merge order

fix(datastore): fence the npm publish and conta... (!2268 - merged) • Pawel Rozlach • 19.4 and fix(maven): register and enqueue metadata recon... (!2297 - merged) • Moaz Khalifa • 19.4 both landed first. The rebase kept both sides of the one conflicting hunk, CommitPublish's commitCtx beside this MR's seventh commitInput argument. Main's tombstone-reaper test also gained a FindOrCreateVersion call after this branch widened the signature, so the rebased tree compiled alone and failed the datastore integration jobs until that call gained its argument.

Governing ADRs

ADR-007 defines both columns as nullable text capped at 255 characters. The write stays inside the cap, and there is no schema change. ADR-020 fixes the token payload: gitlab.local_id is the user id the accessor reads, and the five-member gitlab object carries no project or commit. ADR-021 resolves every credential type to the same User principal, so the credential cannot tell a CI publish from a human one. No deviation.

Testing

Gates run at 17d140ad4:

  • go build ./... and go vet -tags=integration ./....
  • go test on internal/auth/..., internal/datastore, internal/format/maven, internal/format/npm, internal/metrics, and cmd/artifact-registry.
  • The Maven and npm integration suites and the datastore version and reaper suites with -tags=integration, against a postgres:17-alpine started with CI's .pg-service-options.
  • golangci-lint run --build-tags=integration --max-same-issues=0 --max-issues-per-linter=0 --uniq-by-line=false on the touched Go packages: 0 findings on added lines. The default lint on cmd/artifact-registry is clean.
  • scripts/ci/check-comment-caps.sh --base origin/main.
  • markdownlint and Vale on the five docs, lychee through the pre-commit hook.
  • EXPLAIN on the Maven INSERT is byte-identical with and without the column: Insert on maven_versions / Conflict Resolution: NOTHING / Conflict Arbiter Indexes: unique_maven_versions_ns_id_pkg_id_version -> Result.

AC-19, reviewer-runnable. No added Go line names the two unwritten columns:

git diff origin/main...HEAD -- '*.go' | grep -E '^\+' | grep -iE 'gitlab_project_id|GitlabProjectID|git_commit_sha|GitlabGitCommitSha'

e2e catalogs (guardrail 12): docs/testing/e2e/maven.md and docs/testing/e2e/npm.md gain an e2e.<format>.discover.version-publisher row under Discover, blocked because the rig's bootstrap token establishes no user.

Spec coverage

Specs: docs/specs/S17-rest-management-api.md ("Artifact resources (Phase 3)") and docs/specs/S10-maven-hosted.md (Step 4c, Out of Scope).

# Criterion Tests File
AC-1 The accessor yields nil for a nil receiver, AnonymousIdentity(), the zero Identity{}, and a LocalID under OriginUnspecified TestIdentity_GitLabUserID cases nil identity, anonymous, zero value, mis-originated internal/auth/auth_test.go
AC-2 An organization-origin "42" yields "42", and a federated origin or an empty LocalID yields nil TestIdentity_GitLabUserID cases organization 42, federated 42, empty local id internal/auth/auth_test.go
AC-3 Bound: 255 ASCII bytes survive, and 256 bytes, a NUL byte, invalid UTF-8, and 255 two-byte runes (510 bytes) yield nil TestIdentity_GitLabUserID cases 255 bytes, 256 bytes, nul byte, invalid utf-8, 255 runes over the byte bound internal/auth/auth_test.go
AC-4 authtest.Anonymous accepts its token as anonymous, rejects a mismatched, empty, prefix, and suffix token, and an empty configured token fails the test TestAnonymous (5 cases), TestAnonymous_RejectsEmptyToken internal/auth/authtest/fake_test.go
AC-5 The Maven store writes the publisher on the INSERT arm and the conflict arm leaves it: "42" creates, "43" finds, and the column reads "42" both times through FindMavenVersionByID TestMavenVersionStore_FindOrCreateVersion subtest writes the publisher on the insert arm and the conflict arm leaves it internal/datastore/maven_versions_integration_test.go
AC-6 The Maven store binds NULL for a nil publisher TestMavenVersionStore_FindOrCreateVersion subtest binds NULL for a nil publisher internal/datastore/maven_versions_integration_test.go
AC-7 The Maven coordinate guards still reject each bad input with the widened signature TestMavenVersionStore_VersionCoordinateGuards internal/datastore/maven_versions_test.go
AC-8 The npm store writes the publisher, and the package's version list reads it back TestNpmVersionStore_InsertNpmVersion subtest inserts a new version and returns its id internal/datastore/npm_write_integration_test.go
AC-9 A second npm insert of the same version by "43" returns ErrNpmVersionExists and the row still reads "42" TestNpmVersionStore_InsertNpmVersion subtest a second insert of the same version returns ErrNpmVersionExists and writes no row internal/datastore/npm_write_integration_test.go
AC-10 The npm store binds NULL for a nil publisher TestNpmVersionStore_ListNpmVersionsByPackage subtest projects the resource columns and omits package_json, assertion a publish that established no user reads null attribution internal/datastore/npm_versions_list_integration_test.go
AC-11 An authenticated Maven primary-file PUT answers 201 and the version row reads the user id TestUpload_RecordsPublisher case authenticated internal/format/maven/upload_test.go
AC-12 An anonymous Maven publish writes NULL, and a 256-byte, NUL-bearing, or invalid-UTF-8 id rides Basic's base64 and writes NULL rather than 500 TestUpload_RecordsPublisher cases anonymous, over-long id, nul byte, invalid utf-8 internal/format/maven/upload_test.go
AC-13 Sidecar and later Maven uploads by "43" leave "42" on the one live version, every intermediate status asserted with require TestUpload_LaterUploadsKeepTheFirstPublisher internal/format/maven/upload_test.go
AC-14 The Maven fake seam compiles and the 500 path is unchanged TestServePrimaryUpload_StoreError_Yields500 internal/format/maven/upload_internal_test.go
AC-15 An authenticated npm publish answers 201 and npm_versions.gitlab_user_id reads the user id TestPublishCommitIntegration_RecordsPublisher case authenticated internal/format/npm/publish_commit_integration_test.go
AC-16 An anonymous npm publish writes NULL, and a 256-byte or invalid-UTF-8 id rides the Bearer header and writes NULL rather than 500 TestPublishCommitIntegration_RecordsPublisher cases anonymous, over-long id, invalid utf-8 internal/format/npm/publish_commit_integration_test.go
AC-17 An npm republish by "43" answers 409 and the row still reads "42", every intermediate status asserted with require TestPublishCommitIntegration_RepublishKeepsTheFirstPublisher internal/format/npm/publish_commit_integration_test.go
AC-18 The management API serializes the stored id as created_by Existing TestVersionDetailHandler_SerializesPublishAttribution and TestVersionFileHandlersIntegration_MavenWalksAndDetails (created_by reads the stored gitlab_user_id), cited, not duplicated internal/managementapi/version_file_handlers_test.go, internal/managementapi/version_file_read_handlers_integration_test.go
AC-19 No writer, parameter, field, or stub for gitlab_project_id or gitlab_git_commit_sha The grep above returns no line n/a
AC-20 The production Maven adapter binds the id through to the store as a statement argument, so dropping it in wire_maven.go fails a unit test TestMavenStoreAdapterFindOrCreateVersion_BindsPublisher cmd/artifact-registry/wire_maven_adapter_test.go
AC-21 The npm handler forwards the id into NpmPublishCommitInput.GitlabUserID at the committer seam TestPublish_ForwardsPublisherToCommitter internal/format/npm/publish_usagedata_test.go
AC-22 Each created version row is booked under versions_created_total{attributed}, Maven on the created arm only and npm on every 201, and a later Maven upload or a refused npm republish books nothing TestUpload_RecordsPublisher, TestUpload_LaterUploadsKeepTheFirstPublisher, TestPublishCommitIntegration_RecordsPublisher, TestPublishCommitIntegration_RepublishKeepsTheFirstPublisher internal/format/maven/upload_test.go, internal/format/npm/publish_commit_integration_test.go
AC-23 A request with no identity holder commits with NULL attribution, books attributed="false", and logs a WARN rather than answering 500 TestUpload_NoIdentityHolder_RecordsNoPublisherAndWarns, TestPublish_NoIdentityHolder_RecordsNoPublisherAndWarns internal/format/maven/upload_test.go, internal/format/npm/publish_usagedata_test.go
AC-24 Both format registries pass the cardinality audit with the attributed set emitted, and each package's exposure list names the new series TestRegisterMetrics_PassesCardinalityAudit (both packages), TestRegisterMetrics_ExposedViaGatherer, TestRegisterMetrics_ExposesAllOperationalVectors internal/format/maven/metrics_test.go, internal/format/maven/buffered_test.go, internal/format/npm/metrics_test.go

Error cases: the cited spec passages name none of their own. An unstorable id (empty, over 255 bytes, NUL-bearing, or invalid UTF-8) binds NULL and never fails the publish: AC-3 at the accessor, AC-12 and AC-16 at the handlers for the shapes a credential can carry. Measured against net/http: a NUL byte cannot ride a Bearer header (the client refuses it and the server answers 400), so on npm it is accessor-only, while invalid UTF-8 rides Bearer as obs-text and both shapes ride Basic's base64. The empty id is accessor-only on both arms, because ExtractCredential refuses a zero-length credential.

Security: the recorded publisher comes only from the identity the auth chain established, never from a client-supplied field. AC-11, AC-13, AC-15, and AC-17 exercise the real auth.IdentityHolderMiddleware and auth.Middleware pair with one wrapped handler per credential, so a second publisher cannot pass as the first.

Context for LLM agents

Rationale

  • Fill gitlab_user_id on Maven's conflict arm when null. Rejected: it attributes an old version to whoever next uploads a file into it.
  • Write attribution inside the file-commit transaction. Rejected: it re-litigates S10's pool-then-commit design, where the version row commits before the body streams, and that design is a non-goal here.
  • A FindOrCreateMavenVersionInput struct instead of the positional parameter. Rejected: the same 12 call sites change either way, and the struct turns a fix into a seam refactor.
  • (string, bool) instead of *string from the accessor. Rejected: both callers would convert and restate the bound the accessor exists to hold once.
  • Chosen: *string end to end, bounded once in auth.Identity.GitLabUserID, bound into VALUES through the existing nullableStringExpr.

Non-goals

  • gitlab_project_id and gitlab_git_commit_sha. No carrier in the token. The bytea column holds raw digest bytes (20 for SHA-1, 32 for SHA-256) serialized by hex.EncodeToString, so a future writer hex-decodes and rejects a non-hex or wrong-length input.
  • Metering inside internal/auth. local_id is an IAM-issued stringified int64, so the accessor's drop arm is unreachable from a conforming issuer, and a counter in a pure accessor is the wrong layer. The format packages book the outcome instead, where the row is written, so an issuer or wiring change that stops attribution landing moves a signal.
  • Failing the publish when IdentityFromContext returns ok == false. Unreachable on the current wiring, since the holder is seeded outside auth for every request and both routes sit inside auth.Middleware, so publisherFromContext logs a WARN and proceeds unattributed rather than answering 500.
  • A negative-control probe for the no-authtest-in-prod depguard rule. The rule pre-exists and its mechanics are untouched.
  • S11. Its silence on attribution is not a contradiction, and it is another owner's spec.
  • Container/OCI. container_manifests has no attribution columns.

Deployment

On the AR_BOOTSTRAP_TOKEN stub every publish is anonymous and created_by stays null. An observable change needs auth.token_exchange on the target.

Follow-ups, not filed here

  • repositories.gitlab_created_by_user_id has the identical never-written gap, and S17's S08 row is stale on it.
  • ADR-007 describes container_manifests attribution columns no migration created.
  • The ADR-020 CI-claims amendment plus the IAM issuer change that unblocks the two null columns.
  • Federated-origin publishers record no attribution: the accessor admits only the organization origin, and widening it needs a column that carries the origin.
  • No startup log names the live validator.
  • Both catalogs' Authentication intros still say scenarios run under the bootstrap token.
  • Rows created before the fix cannot be backfilled.

Review residue

The test(datastore) commit body names a seedRepoPackage closure a later commit folded into seedPackage. Historical, and the squash removes it. The two docs/plans/ findings from /review-branch are accepted deviations of the working-plan pipeline this MR came from.

Database Review Evidence

Queries

Note

Plans are from EXPLAIN (ANALYZE, BUFFERS) against an ephemeral PostgreSQL 17 container (matching GL_PG_CURR_VERSION from .gitlab-ci-other-versions.yml), with synthesized seed data rolled back per query and the container torn down at the end of the run. Numbers reflect moderate cardinality and do not capture production-scale effects. See Database review evidence for seed sizing, methodology, and the anomalies the skill flags. Expand each row's details for the seed shape, rendered SQL, bound args, and raw plan.

Method Plan node Index Rows (plan / actual) Cost Time Buffers (hit / read) Partitions
datastore.MavenVersionStore.FindOrCreateVersion.UserSet Insert unique_maven_versions_ns_id_pkg_id_version (arbiter) 1 / 1 0.01 0.581ms 112 / 1 1/64
datastore.MavenVersionStore.FindOrCreateVersion.UserNil Insert unique_maven_versions_ns_id_pkg_id_version (arbiter) 1 / 1 0.01 0.482ms 84 / 1 1/64
datastore.NpmVersionStore.InsertNpmVersion.UserSet Insert unique_npm_versions_ns_id_pkg_id_version (arbiter) 1 / 1 0.01 0.468ms 104 / 1 1/64
datastore.NpmVersionStore.InsertNpmVersion.UserNil Insert unique_npm_versions_ns_id_pkg_id_version (arbiter) 1 / 1 0.01 0.428ms 70 / 1 1/64
datastore.MavenVersionStore.FindOrCreateVersion.UserSet

Summary: Single-row Insert with unique_maven_versions_ns_id_pkg_id_version as the conflict arbiter, routed to one partition (maven_versions_p13 by tableoid). The plan text is byte-identical to the merge-base statement without gitlab_user_id, under EXPLAIN (COSTS OFF) and with costs (width=208 in both). A second EXECUTE on the same coordinates bound to '43' reports Conflicting Tuples: 1 and the row still reads '42'. No anomalies.

Seed shape: namespaces=1, repositories=1, maven_repositories=1, maven_packages=1

Rendered SQL:

INSERT INTO public.maven_versions (id, namespace_id, maven_package_id, version, gitlab_user_id)
VALUES ($1::uuid, $2::uuid, $3::uuid, $4::text, $5::text)
ON CONFLICT (namespace_id, maven_package_id, version) WHERE soft_deleted_at IS NULL DO NOTHING
RETURNING maven_versions.namespace_id AS "maven_versions.namespace_id",
          maven_versions.id AS "maven_versions.id",
          maven_versions.maven_package_id AS "maven_versions.maven_package_id",
          maven_versions.version AS "maven_versions.version";

Bound args: [394d7237-c918-7b26-9c15-0a6a59f3fbc3, edbaad9e-2b6c-7e15-b11a-82602c51cc93, ad9bf990-bc02-7e67-9ebb-0748771f7d34, 1.0.0, 42]

Plan (EXPLAIN (ANALYZE, BUFFERS) output):

Insert on maven_versions  (cost=0.00..0.01 rows=1 width=208) (actual time=0.581..0.581 rows=1 loops=1)
  Conflict Resolution: NOTHING
  Conflict Arbiter Indexes: unique_maven_versions_ns_id_pkg_id_version
  Tuples Inserted: 1
  Conflicting Tuples: 0
  Buffers: shared hit=112 read=1 dirtied=17 written=9
  ->  Result  (cost=0.00..0.01 rows=1 width=208) (actual time=0.001..0.002 rows=1 loops=1)
Planning:
  Buffers: shared hit=163
Planning Time: 0.475 ms
Trigger for constraint fk_maven_versions_maven_package_id_maven_packages on maven_versions_p13: time=1.146 calls=1
Trigger for constraint fk_maven_versions_namespace_id_namespaces on maven_versions_p13: time=0.299 calls=1
Execution Time: 2.563 ms

Timings: planning 0.475ms, execution 2.563ms, total 3.038ms.

datastore.MavenVersionStore.FindOrCreateVersion.UserNil

Summary: Same plan as the bound branch with NULL::text inline: single-row Insert, arbiter unique_maven_versions_ns_id_pkg_id_version, routed to maven_versions_p00. The stored gitlab_user_id reads NULL. No anomalies.

Seed shape: namespaces=1, repositories=1, maven_repositories=1, maven_packages=1

Rendered SQL:

INSERT INTO public.maven_versions (id, namespace_id, maven_package_id, version, gitlab_user_id)
VALUES ($1::uuid, $2::uuid, $3::uuid, $4::text, NULL::text)
ON CONFLICT (namespace_id, maven_package_id, version) WHERE soft_deleted_at IS NULL DO NOTHING
RETURNING maven_versions.namespace_id AS "maven_versions.namespace_id",
          maven_versions.id AS "maven_versions.id",
          maven_versions.maven_package_id AS "maven_versions.maven_package_id",
          maven_versions.version AS "maven_versions.version";

Bound args: [cae910a4-fb1c-75ec-8cb8-75a817250af5, 902c1a9e-8153-72e9-adde-6ebda4ce2a96, f65597ce-ac86-7f7a-b98b-8f92986044a5, 1.0.0]

Plan (EXPLAIN (ANALYZE, BUFFERS) output):

Insert on maven_versions  (cost=0.00..0.01 rows=1 width=208) (actual time=0.481..0.482 rows=1 loops=1)
  Conflict Resolution: NOTHING
  Conflict Arbiter Indexes: unique_maven_versions_ns_id_pkg_id_version
  Tuples Inserted: 1
  Conflicting Tuples: 0
  Buffers: shared hit=84 read=1 dirtied=17 written=9
  ->  Result  (cost=0.00..0.01 rows=1 width=208) (actual time=0.001..0.001 rows=1 loops=1)
Planning:
  Buffers: shared hit=156
Planning Time: 0.459 ms
Trigger for constraint fk_maven_versions_maven_package_id_maven_packages on maven_versions_p00: time=0.578 calls=1
Trigger for constraint fk_maven_versions_namespace_id_namespaces on maven_versions_p00: time=0.103 calls=1
Execution Time: 1.268 ms

Timings: planning 0.459ms, execution 1.268ms, total 1.727ms.

datastore.NpmVersionStore.InsertNpmVersion.UserSet

Summary: Single-row Insert with unique_npm_versions_ns_id_pkg_id_version as the conflict arbiter, routed to one partition (npm_versions_p29 by tableoid). The plan text is byte-identical to the merge-base statement without gitlab_user_id, under EXPLAIN (COSTS OFF) and with costs (width=240 in both). A second EXECUTE on the same coordinates bound to '43' reports Conflicting Tuples: 1 and the row still reads '42'. No anomalies.

Seed shape: namespaces=1, repositories=1, npm_repositories=1, npm_packages=1

Rendered SQL:

INSERT INTO public.npm_versions (id, namespace_id, npm_package_id, version, size_bytes, package_json, gitlab_user_id)
VALUES ($1::uuid, $2::uuid, $3::uuid, $4::text, $5, $6::text::jsonb, $7::text)
ON CONFLICT (namespace_id, npm_package_id, version) WHERE soft_deleted_at IS NULL DO NOTHING
RETURNING npm_versions.id AS "npm_versions.id";

Bound args: [7b27d43c-48ed-794e-a51d-8003e23fe6e3, 8ceb803c-9038-7af3-bb6c-982e76052b5c, b924800a-19ff-7367-9620-e0bc1500c45a, 1.0.0, 1234, {"name":"review-prep-npm","version":"1.0.0"}, 42]

Plan (EXPLAIN (ANALYZE, BUFFERS) output):

Insert on npm_versions  (cost=0.00..0.01 rows=1 width=240) (actual time=0.467..0.468 rows=1 loops=1)
  Conflict Resolution: NOTHING
  Conflict Arbiter Indexes: unique_npm_versions_ns_id_pkg_id_version
  Tuples Inserted: 1
  Conflicting Tuples: 0
  Buffers: shared hit=104 read=1 dirtied=13 written=7
  ->  Result  (cost=0.00..0.01 rows=1 width=240) (actual time=0.001..0.002 rows=1 loops=1)
Planning:
  Buffers: shared hit=136 read=1
Planning Time: 0.420 ms
Trigger for constraint fk_npm_versions_namespace_id_namespaces on npm_versions_p29: time=0.143 calls=1
Trigger for constraint fk_npm_versions_npm_package_id_npm_packages on npm_versions_p29: time=1.173 calls=1
Execution Time: 2.291 ms

Timings: planning 0.420ms, execution 2.291ms, total 2.711ms.

datastore.NpmVersionStore.InsertNpmVersion.UserNil

Summary: Same plan as the bound branch with NULL::text inline: single-row Insert, arbiter unique_npm_versions_ns_id_pkg_id_version, routed to npm_versions_p41. The stored gitlab_user_id reads NULL. No anomalies.

Seed shape: namespaces=1, repositories=1, npm_repositories=1, npm_packages=1

Rendered SQL:

INSERT INTO public.npm_versions (id, namespace_id, npm_package_id, version, size_bytes, package_json, gitlab_user_id)
VALUES ($1::uuid, $2::uuid, $3::uuid, $4::text, $5, $6::text::jsonb, NULL::text)
ON CONFLICT (namespace_id, npm_package_id, version) WHERE soft_deleted_at IS NULL DO NOTHING
RETURNING npm_versions.id AS "npm_versions.id";

Bound args: [9e1f2e9a-51ff-76ee-8e39-58755ccfc046, 67188e4f-b897-7bae-88c3-d2a42fc6bee0, 9d421bf3-2f64-7ce9-82b5-b3e3cccf35c7, 1.0.0, 1234, {"name":"review-prep-npm","version":"1.0.0"}]

Plan (EXPLAIN (ANALYZE, BUFFERS) output):

Insert on npm_versions  (cost=0.00..0.01 rows=1 width=240) (actual time=0.428..0.428 rows=1 loops=1)
  Conflict Resolution: NOTHING
  Conflict Arbiter Indexes: unique_npm_versions_ns_id_pkg_id_version
  Tuples Inserted: 1
  Conflicting Tuples: 0
  Buffers: shared hit=70 read=1 dirtied=13 written=7
  ->  Result  (cost=0.00..0.01 rows=1 width=240) (actual time=0.001..0.001 rows=1 loops=1)
Planning:
  Buffers: shared hit=128
Planning Time: 0.400 ms
Trigger for constraint fk_npm_versions_namespace_id_namespaces on npm_versions_p41: time=0.149 calls=1
Trigger for constraint fk_npm_versions_npm_package_id_npm_packages on npm_versions_p41: time=0.626 calls=1
Execution Time: 1.301 ms

Timings: planning 0.400ms, execution 1.301ms, total 1.701ms.

Related to #1151 (closed)

Edited by Hayley Swimelar

Merge request reports

Loading
Loading