# PROVENANCE

This branch was produced by an AI agent.  Everything below records how.

## Model and tooling

| | |
|---|---|
| Orchestrator model | Claude Opus 5 (`claude-opus-5`) |
| Hunt sub-agent model | Claude Sonnet 5 (`claude-sonnet-5`) |
| Harness | GitHub Copilot CLI, version 1.0.82 |
| Date of run | 2026-09-03 (UTC) |
| Host | Linux, 2 CPUs, 15 GB RAM |

## Prompt

The task was given by user `@nmisch` in a single message, reproduced verbatim:

> Make a large workflow, with at most 270 agents, to write test cases covering
> user-visible defects in the new FOR PORTION OF feature (commit 8e72d91) that
> are still present in master.  Use your own worktree; disregard the present dir
> except as repository to which to attach your worktree.  The workflow should
> first look for extant user-visible defects.  If it finds any, write a test
> case covering some of those defects.  If any defects found weren't suitable to
> test, describe them in a report.
>
> Commit the following on a fresh branch:
> - A report describing any defects found, testable or not.  Prefix the report
>   with [no defects] if that's so.
> - Any tests written
> - A PROVENANCE.md file containing model, prompt, etc.

No other human input, guidance, or correction was given at any point.

## Subject under test

| | |
|---|---|
| Feature commit | `8e72d914c52876525a90b28444453de8085c866f` — "Add UPDATE/DELETE FOR PORTION OF" (2026-04-01) |
| Baseline | `master` = `0b776de09ed3e237181def135577321bdd31b548` (2026-09-03) |
| Version string | PostgreSQL 20devel |
| Branch created | `copilot/8e72d91-for-portion-of-defects`, branched from `0b776de` |

## Workflow

**1. Isolated worktree and build.**  A dedicated worktree was attached to the
repository found in the working directory; nothing in that directory was
modified.  The worktree was configured with meson
(`-Dcassert=true -Ddebug=true -Doptimization=0 -Dtap_tests=enabled`) so that
any `Assert` reachable from SQL would trip, and installed to a private prefix.

**2. Sandbox harness.**  A per-agent PostgreSQL sandbox was built: a
pre-`initdb`'d template cluster plus a `pgenv.sh` driver giving each agent an
isolated slot (`start`/`stop`/`reset`/`sql`/`psql`/`log`).  Each slot uses its
own data directory as its Unix socket directory, so agents could run clusters
concurrently with no port or path collisions.

**3. Ground-truth survey.**  All follow-up commits to `8e72d91` were
enumerated and checked with `git merge-base --is-ancestor`.  All 19 are
already contained in `0b776de`, so no already-fixed bug could be
mistaken for a live one.  The list was written into the agent briefing as a
"do not report these" section, together with a definition of "user-visible
defect" (something a user can observe through SQL, client protocol,
documentation, or error output — not an internal code smell), a requirement
that every finding carry a control case proving the non-temporal equivalent
behaves correctly, and a fixed output format for findings.

**4. Decomposition.**  The feature's surface was decomposed into **82 hunt
areas** (parser, rewriter, planner, executor, triggers, partitioning,
inheritance, views and rules, RLS and privileges, constraints, temporal keys,
concurrency, deparse, documentation claims, error-message audit, and an
"incomplete fix" audit of each of the 19 follow-up commits).  Each area became
a self-contained assignment file.

**5. Agent waves.**  Hunt agents were launched in waves against those
assignments — **33 agents in total**, well inside the 270 budget.  The runtime
enforces a hard cap of 32 concurrent background agents, which was reached; the
remaining 49 hunt areas were therefore never dispatched.

**6. Observed limitation, and the pivot.**  At 32-way concurrency the fleet
was throughput-starved: for roughly the first 70 minutes, 32 of the 33 agents
completed zero turns and issued zero tool calls, while the one agent launched
when only eight were running finished normally in 31 minutes.  Rather than
wait, the orchestrator hunted directly, in parallel with the stalled fleet,
and committed an initial report and test set covering the three defects it had
found on its own.

The fleet then unblocked — once the orchestrator stopped competing for
throughput, agents began finishing at a steady rate, each taking roughly
4,400–6,000 seconds end to end.  **32 of the 33 agents returned a final
report** before this branch was finalized; the 33rd (NULL/empty ranges) had
already written its findings file, recording `NONE`, but had not yet returned
its summary.  All results were triaged afterwards and substantially expanded
the report — including the most serious defect in it.

The practical lesson, recorded here because it shaped the result: for this
runtime, agent fan-out should be sized at roughly 8–12 concurrent agents.  A
32-wide fleet does eventually deliver, but it front-loads a long dead period
in which no agent makes progress.

**7. Findings accounting.**  Of the 33 agents, **23 reported `NONE`** and 10
reported at least one candidate defect.  Attribution of the 14
findings in the report:

| Source | Findings |
|---|---|
| Hunt agents | D1 (rules on views — the most serious), D5, D6, D7, D8, D9, D11 |
| Orchestrator | D2, D3, D4, D10, D12, D13, D14 |
| Both, independently | D2 (agent h80 rediscovered it with the same root cause); D5 (agents h57 and h64 found it independently of each other) |

**8. Triage and false positives.**  Agent findings were **not** taken on
trust.  Every claim was re-derived by hand on an unmodified `0b776de` before
being written into the report, and the ones that did not survive are listed in
the report's "Rejected candidate findings" section.  This mattered: one
finding (h27-1) was a false positive — the behaviour it described is already
covered by an existing test that deliberately captures it — and one (h57-1)
could not be reproduced from the agent's summary at all until the agent was
asked, in a follow-up turn, for its exact script.  The missing ingredient was
that GiST support function 12 must be registered with `("any","any")`
lefttype/righttype rather than the concrete range type; with that detail the
`XX000` reproduced immediately.  Roughly one in five agent findings needed
either correction or outright rejection.

**9. Method.**  Differential testing against independently computed ground
truth, plus systematic comparison of each `FOR PORTION OF` construct against
its hand-written non-temporal equivalent.  Notably, ~700 combinations of row
range × target bounds were compared against `range_intersect` /
`multirange_minus` results (no mismatch — the core range algebra is sound),
which redirected the search toward the feature's boundaries with other
subsystems.  That is where every reported defect lives: the rewriter's
interaction with rules, `EXPLAIN`, parameter type resolution, trigger timing,
inheritance, and opclass assumptions.

**10. Verification.**  Each finding was reproduced from a clean cluster with
an explicit control case demonstrating that the non-temporal equivalent
behaves correctly.  Candidate root-cause fixes were then applied
**temporarily** to confirm the diagnosis and to generate trustworthy expected
output for the new tests — the expected output was *generated from a working
fix*, never hand-written — verified to leave all 2795 lines of pre-existing
expected output unchanged, and then reverted.  The committed tree contains
**no source changes**: `git diff` against `0b776de` touches only
`src/test/regress/`, the report, and this file.

## What is committed

| File | Contents |
|---|---|
| `FOR-PORTION-OF-DEFECTS.md` | The report: 4 tested defects, 10 described-but-untested findings, root-cause analysis, rejected candidates, and a coverage list of areas probed without finding anything |
| `src/test/regress/sql/for_portion_of.sql` | Two new test blocks: `fpo_param` (parameter type inference; `EXPLAIN` and `EXPLAIN (GENERIC_PLAN)`) and `fpo_instead_rule` (`FOR PORTION OF` on views with `INSTEAD`/`INSTEAD NOTHING`/`ALSO` rules) |
| `src/test/regress/expected/for_portion_of.out` | Matching expected output, encoding **correct** behaviour |
| `PROVENANCE.md` | This file |

## How to read the test result

The new tests deliberately encode correct behaviour, so **they fail on
`0b776de`**, and that failure diff *is* the defect demonstration:

```
build/src/test/regress/pg_regress --bindir=<prefix>/bin \
    --inputdir=src/test/regress --expecteddir=src/test/regress \
    --dlpath=build/src/test/regress --temp-instance=/tmp/ti for_portion_of
```

produces a 190-line, 5-hunk diff: 11 unexpected `ERROR` lines (D2/D3/D4), 3
missing `ERROR` lines (D1), and the wrong row contents that D1 leaves behind —
a renamed whole row and, for `DELETE`, an empty table.  All hunks are confined
to the two new test blocks.  With the three candidate fixes described in the
report's "Root causes" section applied, the test passes.

## Caveats

* 49 of the 82 identified hunt areas were never dispatched, because the
  runtime's 32-agent concurrency cap was reached.  They should be considered
  **unexamined**, not clean.
* The report's "areas examined without finding a defect" list is assembled
  from the orchestrator's own probes and from 23 agents that reported `NONE`.
  Those agents' negative results were spot-checked for plausibility but, being
  negatives, were not independently re-derived the way the positive findings
  were.
* Ten of the fourteen findings are described rather than tested.  In most
  cases that is a deliberate judgement recorded in the report: the correct
  behaviour is a design question whose resolution would change the expected
  output, so pinning today's behaviour would enshrine a bug and pinning a
  guess would prejudge the fix.
* Concurrency and crash-recovery behaviour was only lightly probed; the
  existing isolation spec documents a known `READ COMMITTED` limitation that
  was treated as documented behaviour rather than a defect.
