Commit Graph

6 Commits

Author SHA1 Message Date
5043532d30 fix(go): remove ineffectual pgplugin index increment
Some checks failed
Harness Replays / detect-changes (pull_request) Successful in 14s
Lint curl status-code capture / Scan workflows for curl status-capture pollution (pull_request) Successful in 14s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 1m5s
review-check-tests / review-check.sh regression tests (pull_request) Successful in 19s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m21s
lint-continue-on-error-tracking / lint-continue-on-error-tracking (pull_request) Successful in 2m15s
Lint pre-flip continue-on-error / Verify continue-on-error flips have run-log proof (pull_request) Successful in 2m17s
Lint workflow YAML (Gitea-1.22.6-hostile shapes) / Lint workflow YAML for Gitea-1.22.6-hostile shapes (pull_request) Successful in 1m40s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 46s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 23s
qa-review / approved (pull_request) Failing after 25s
lint-required-context-exists-in-bp / lint-required-context-exists-in-bp (pull_request) Successful in 2m35s
gate-check-v3 / gate-check (pull_request) Successful in 38s
security-review / approved (pull_request) Failing after 26s
sop-checklist-gate / gate (pull_request) Successful in 26s
sop-tier-check / tier-check (pull_request) Successful in 23s
Ops Scripts Tests / Ops scripts (unittest) (pull_request) Successful in 1m32s
CI / Canvas (Next.js) (pull_request) Successful in 9s
sop-checklist / all-items-acked (pull_request) acked: 7/7
CI / Shellcheck (E2E scripts) (pull_request) Successful in 10s
CI / Python Lint & Test (pull_request) Successful in 13s
Harness Replays / Harness Replays (pull_request) Successful in 11s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 17s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 13s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 10s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 2m27s
audit-force-merge / audit (pull_request) Successful in 27s
CI / Platform (Go) (pull_request) Failing after 16m11s
CI / all-required (pull_request) Successful in 13s
2026-05-13 14:32:41 -07:00
ecdae882b6 Merge pull request 'feat(canvas): mount SearchDialog in desktop + mobile canvas shells' (#837) from design/826-searchdialog-mount-v2 into main
Some checks failed
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 17s
E2E API Smoke Test / detect-changes (pull_request) Successful in 41s
CI / Detect changes (pull_request) Successful in 41s
Harness Replays / detect-changes (pull_request) Successful in 17s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 51s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 50s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 15s
qa-review / approved (pull_request) Failing after 17s
sop-checklist-gate / gate (pull_request) Successful in 18s
security-review / approved (pull_request) Failing after 20s
sop-tier-check / tier-check (pull_request) Successful in 16s
gate-check-v3 / gate-check (pull_request) Successful in 27s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 43s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 7s
CI / Canvas (Next.js) (pull_request) Successful in 11s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m16s
CI / Python Lint & Test (pull_request) Successful in 8s
Harness Replays / Harness Replays (pull_request) Successful in 8s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 15s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 11s
sop-checklist / all-items-acked (pull_request) [info tier:low] acked: 0/7 — missing: comprehensive-testing, local-postgres-e2e, staging-smoke, +4 — body-unfilled: comprehensive-testing, l
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 9s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 1m49s
CI / Platform (Go) (pull_request) Failing after 3m53s
CI / all-required (pull_request) Successful in 3s
2026-05-13 14:20:08 +00:00
4b5614cbdd fix(memory/pgplugin): restore idx++ in PatchNamespace (OFFSEC-004)
Some checks failed
CI / Detect changes (pull_request) Successful in 1m15s
Harness Replays / detect-changes (pull_request) Successful in 26s
E2E API Smoke Test / detect-changes (pull_request) Successful in 1m25s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 20s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 1m19s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 1m5s
qa-review / approved (pull_request) Failing after 19s
gate-check-v3 / gate-check (pull_request) Successful in 32s
security-review / approved (pull_request) Failing after 18s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 49s
sop-checklist-gate / gate (pull_request) Successful in 22s
sop-tier-check / tier-check (pull_request) Successful in 17s
CI / Canvas (Next.js) (pull_request) Successful in 14s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m28s
CI / Platform (Go) (pull_request) Failing after 5m25s
sop-checklist / all-items-acked (pull_request) [info tier:low] acked: 0/7 — missing: comprehensive-testing, local-postgres-e2e, staging-smoke, +4 — body-unfilled: comprehensive-testing, l
CI / Shellcheck (E2E scripts) (pull_request) Successful in 10s
CI / Python Lint & Test (pull_request) Successful in 12s
Harness Replays / Harness Replays (pull_request) Successful in 9s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 18s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 13s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 5m17s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 16s
CI / all-required (pull_request) Successful in 5s
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 25s
audit-force-merge / audit (pull_request) Successful in 47s
Commit ad7acd30 removed this increment as a golangci-lint false-positive
("unused variable: idx") — idx is used in the query string built by
fmt.Sprintf, so the lint was wrong. The removal broke the dual-field
case: when both ExpiresAt and Metadata are set, the query uses \$3 for
metadata but args only has 3 elements (indices 0=name, 1=expires, 2=metadata),
so \$3 is out-of-bounds or reads the wrong value.

Fix: restore idx++ after the metadata args append.

Test: add TestStore_PatchNamespace_DualFields — covers the previously
untested case where both expires_at and metadata are patched in one call.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 11:35:07 +00:00
ad7acd30db fix(platform): clear golangci-lint findings
Some checks failed
E2E API Smoke Test / detect-changes (pull_request) Successful in 1m0s
Lint curl status-code capture / Scan workflows for curl status-capture pollution (pull_request) Successful in 14s
E2E Staging SaaS (full lifecycle) / pr-validate (pull_request) Successful in 54s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 42s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m15s
lint-continue-on-error-tracking / lint-continue-on-error-tracking (pull_request) Successful in 1m50s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 16s
qa-review / approved (pull_request) Failing after 15s
Lint pre-flip continue-on-error / Verify continue-on-error flips have run-log proof (pull_request) Successful in 2m0s
Lint workflow YAML (Gitea-1.22.6-hostile shapes) / Lint workflow YAML for Gitea-1.22.6-hostile shapes (pull_request) Successful in 1m36s
lint-mask-pr-atomicity / lint-mask-pr-atomicity (pull_request) Successful in 2m8s
gate-check-v3 / gate-check (pull_request) Successful in 32s
security-review / approved (pull_request) Failing after 18s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 41s
lint-required-context-exists-in-bp / lint-required-context-exists-in-bp (pull_request) Successful in 2m11s
sop-checklist-gate / gate (pull_request) Successful in 17s
Harness Replays / Harness Replays (pull_request) Successful in 5s
sop-tier-check / tier-check (pull_request) Successful in 22s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 20s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 14s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 10s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 1m42s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 3m53s
CI / Python Lint & Test (pull_request) Successful in 7m18s
CI / Canvas (Next.js) (pull_request) Successful in 11m54s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
CI / Platform (Go) (pull_request) Successful in 12m45s
CI / all-required (pull_request) Successful in 3s
sop-checklist / all-items-acked (pull_request) acked: 7/7
audit-force-merge / audit (pull_request) Successful in 4s
2026-05-12 22:53:22 -07:00
Hongming Wang
1e97fb9a16 Memory v2 fixup C1: backfill idempotency via MemoryWrite.id
Self-review (post-merge) flagged that the backfill claimed to be
idempotent on re-run but actually duplicates every row because the
plugin's INSERT uses gen_random_uuid() and ignores any id passed in.

Fix is contract-level: extend MemoryWrite with an optional `id`
idempotency key. When supplied, the plugin MUST treat the write as
upsert keyed on this id; when omitted, the plugin generates a fresh
UUID (production agent commits keep working unchanged).

Changes:
  * docs/api-protocol/memory-plugin-v1.yaml: add id field with
    description that flags it as idempotency key
  * internal/memory/contract/contract.go: add ID to MemoryWrite struct,
    update memory_write_minimal golden vector
  * internal/memory/pgplugin/store.go: split CommitMemory into two
    paths — upsert when body.ID set (INSERT ... ON CONFLICT (id) DO
    UPDATE), plain INSERT otherwise
  * cmd/memory-backfill/main.go: pass agent_memories.id to MemoryWrite,
    fix the false comment about 409 deduplication

New tests:
  * pgplugin: TestCommitMemory_WithIDUpserts pins the upsert SQL is
    used when id is set; TestCommitMemory_UpsertScanError covers the
    error branch
  * backfill: TestBackfill_PassesSourceUUIDAsIdempotencyKey pins the
    forwarding behavior; TestBackfill_RerunIsIdempotent simulates a
    retry and asserts both runs pass the same uuid (plugin upsert is
    what makes this safe)

Why this matters: operators retrying a failed backfill (which they
will — networks fail, transactions abort) would otherwise create N
duplicates per memory. The duplicates aren't visible until search
results show obvious dupes — debugging that under prod load is bad.

Production agent commits are unaffected: they leave id empty, the
plugin generates a fresh UUID via gen_random_uuid(), zero behavior
change for the hot path.
2026-05-04 08:54:13 -07:00
Hongming Wang
ff5f4cbf7c Memory v2 PR-3: built-in postgres plugin server + schema migrations
Builds on merged PR-1 (#2729), independent of PR-2/PR-4.

Implements every endpoint of the v1 plugin contract behind an HTTP
server (cmd/memory-plugin-postgres/) backed by postgres. Operators
run this binary next to workspace-server; it's the default
implementation MEMORY_PLUGIN_URL points at.

What ships:
  - cmd/memory-plugin-postgres/main.go: boot, signal-driven shutdown,
    boot-time migrations, configurable LISTEN/DATABASE/MIGRATION_DIR
  - cmd/memory-plugin-postgres/migrations/001_memory_v2.up.sql:
      memory_namespaces (PK on name, kind CHECK, expires_at, metadata)
      memory_records (FK to namespaces with CASCADE, kind+source CHECK,
                      pgvector embedding, FTS tsvector, ivfflat partial
                      index on embedding, partial index on expires_at)
  - internal/memory/pgplugin/store.go: storage layer using lib/pq
  - internal/memory/pgplugin/handlers.go: HTTP layer (no router dep —
    a switch on URL.Path keeps the binary's dep surface tiny)
  - 100% statement coverage on store.go + handlers.go

Schema notes:
  - These tables live next to the plugin binary, NOT in workspace-
    server/migrations/. When operators swap the plugin, these tables
    become orphaned (operator drops manually). Documented in PR-10.
  - Search supports semantic (pgvector cosine) → FTS (>=2 char query)
    → ILIKE (1-char query) → recent-listing (no query), with a TTL
    filter applied uniformly across all paths.
  - DELETE on namespace cascades to memory_records (FK ON DELETE
    CASCADE) — a deleted namespace immediately frees its memories.

Coverage corner cases pinned:
  - Health: ok, degraded (db ping fails), no-ping fn
  - Every CRUD endpoint: happy path, bad name, bad JSON, bad body,
    not-found, store errors, exec/scan/marshal errors
  - Search: FTS, semantic, short-query (ILIKE), no-query (recent),
    kinds filter, store errors, scan errors, mid-iteration row error
  - Routing edge cases: unknown path, empty namespace, unknown sub,
    method-not-allowed, GET on /v1/health (allowed), POST on /v1/health
    (404), GET on /v1/search (404)
  - Helper internals: marshalMetadata (nil/happy/unmarshalable),
    nullTime (nil/non-nil), vectorString (empty/format),
    nullVectorString (empty/non-empty), scanNamespace +
    scanMemory metadata-decode errors

No callers in workspace-server yet; integration starts in PR-5
(MCP handlers wire the plugin client through to MCP tools).
2026-05-04 07:31:56 -07:00