Skip to content

lanes-index never bootstraps a Postgres store: psql's "does not exist" error is read from its last line, the caret, so the store is called unreachable #244

Open

Description

@brettheap

Found during the delta check of #219. The defect is on main as well. #219 neither causes it nor fixes it.

The defect

lanes-index never bootstraps a Postgres store whose tables are missing. It calls the store unreachable and writes nothing, so sync exits 1 and export gives up with why = unreachable: followed by spaces and ^.

Line numbers are on main f5c3bcd. On #219's head 5bf29d9 they are :1321, :1355, :1365 and :989.

  1. PostgresStore._run keeps only the last line of psql's stderr (lanes-index:1284). It raises StoreUnusable("unreachable", err[-1]). When the server gives a position, real psql prints three lines:

    • the ERROR: line;
    • a LINE 1: excerpt;
    • a caret line.

    So the detail that _run keeps is the caret.

  2. The "does not exist" check never matches (lanes-index:1313). open_read looks for "does not exist" in exc.detail, and the detail is only ^. So a missing schema_version table is reported as unreachable instead of wiped. open_write (:1323) bootstraps only on wiped, so the DDL never runs.

  3. ddl() has no CREATE SCHEMA (lanes-index:985). Even if (2) matched, open_write would fail on a schema that does not exist yet. Its first CREATE TABLE IF NOT EXISTS "<schema>".schema_version fails with ERROR: schema "<schema>" does not exist, and _run would again keep only the caret line.

The tests miss all of this because FAKE_PSQL in tests/test_lanes_index.py never fails. It models a missing store as an empty answer to the version read. That takes the "no schema_version row" path to wiped, and the fake's DDL "creates" the version.

Repro (postgres:16, 16.15)

Setup

  • Server: a throwaway postgres:16 container (--network none, trust auth). psql is reached through a wrapper that runs docker exec -i <container> psql "$@".
  • Configuration: url= and reader_url= both postgresql://postgres@localhost/postgres, and schema= a fresh name for each case.
  • The helper: LANES_EDIT is a stub lanes-edit.sh that answers workstation (Eagle, env) and prints one TREE line for worktrees --all.
  • The environment: every LANES_* and TMUX variable is unset.
  • The commands: lanes-index sync --source inventory, then lanes-index export --out <dir> --worktrees.
indexer case sync export why tables afterwards
main f5c3bcd no schema rc=1 lanes-index: unreachable: ^ - nothing written rc=3 unreachable: ^ 0
main f5c3bcd schema created, no tables rc=1, same rc=3, same 0
#219 head 5bf29d9 no schema rc=1, same rc=3, same 0
#219 head 5bf29d9 schema created, no tables rc=1, same rc=3, same 0

The spaces before ^ are shortened above. The real detail is psql's caret line, indented to the error's column.

psql's own stderr for the indexer's first read, COPY (SELECT version FROM "<schema>".schema_version) TO STDOUT; (rc=3):

ERROR:  relation "repro6_absent.schema_version" does not exist
LINE 1: COPY (SELECT version FROM "repro6_absent".schema_version) TO...
                                  ^

open_write's own script, built from ddl("postgres", "repro6_absent"), against a schema that does not exist (rc=3):

ERROR:  schema "repro6_absent" does not exist
LINE 1: CREATE TABLE IF NOT EXISTS "repro6_absent".schema_version (v...
                                   ^

What a fix needs to decide

  • How _run reports a failure. It could keep the ERROR: line rather than the last line: the first line that starts ERROR: or FATAL:, or the whole stderr. It could also run psql with -v VERBOSITY=terse, which prints the error on one line. Then a missing table classifies as wiped, and other failures name their real cause instead of a caret.
  • Whether open_write creates the schema (CREATE SCHEMA IF NOT EXISTS) or refuses with a message that names it. The writer role may not have CREATE on the database, so an explicit refusal may be the right answer where QA provisions schemas.
  • A test the fake cannot fake. A fake psql that fails as real psql does (rc=3 and the three-line error) for a missing relation, so the wiped path and the bootstrap are proven against psql's real shape.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions