mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-21 16:27:18 +02:00
Merge master and preserve bounded policy reads in admission batches
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
commit
4d468f998b
204 files changed
+16988
-4053
No files matched your search
@@ -33,12 +33,6 @@ function fixture(): { filePath: string; info: PaperclipRuntimeInfo } {
|
||||
}
|
||||
|
||||
describe("runtime info", () => {
|
||||
it("writes and reads the selected runtime endpoint", () => {
|
||||
const { filePath, info } = fixture();
|
||||
writeRuntimeInfo(info, filePath);
|
||||
expect(readRuntimeInfo("default", filePath)).toEqual(info);
|
||||
});
|
||||
|
||||
it("does not remove runtime info owned by a replacement process", () => {
|
||||
const { filePath, info } = fixture();
|
||||
writeRuntimeInfo(info, filePath);
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { bytesToPortableFileEntry, isBlobStorePath, readZipArchive } from "../commands/client/zip.js";
|
||||
import { createStoredZipArchive } from "./helpers/zip.js";
|
||||
|
||||
describe("isBlobStorePath", () => {
|
||||
it("matches blobs/ entries at the archive root and under a package root", () => {
|
||||
expect(isBlobStorePath("blobs/4f2d1c9a")).toBe(true);
|
||||
expect(isBlobStorePath("paperclip-demo/blobs/4f2d1c9a")).toBe(true);
|
||||
expect(isBlobStorePath("tasks/pap-1/TASK.md")).toBe(false);
|
||||
expect(isBlobStorePath("blobs/nested/file")).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("bytesToPortableFileEntry", () => {
|
||||
it("keeps blobs/ entries as base64 octet streams regardless of extension", () => {
|
||||
const bytes = new Uint8Array([0x00, 0x01, 0x80, 0xfe, 0xff]);
|
||||
expect(bytesToPortableFileEntry("blobs/4f2d1c9a", bytes)).toEqual({
|
||||
encoding: "base64",
|
||||
data: Buffer.from(bytes).toString("base64"),
|
||||
contentType: "application/octet-stream",
|
||||
});
|
||||
});
|
||||
|
||||
it("falls back to base64 when bytes are not valid UTF-8", () => {
|
||||
const invalidUtf8 = new Uint8Array([0x68, 0x69, 0xff, 0xfe, 0xc0]);
|
||||
expect(bytesToPortableFileEntry("tasks/pap-1/raw-notes", invalidUtf8)).toEqual({
|
||||
encoding: "base64",
|
||||
data: Buffer.from(invalidUtf8).toString("base64"),
|
||||
contentType: "application/octet-stream",
|
||||
});
|
||||
});
|
||||
|
||||
it("decodes valid UTF-8 entries to text", () => {
|
||||
const bytes = new TextEncoder().encode("# Notes\n\ncafé ✅\n");
|
||||
expect(bytesToPortableFileEntry("tasks/pap-1/TASK.md", bytes)).toBe("# Notes\n\ncafé ✅\n");
|
||||
});
|
||||
});
|
||||
|
||||
describe("readZipArchive", () => {
|
||||
it("round-trips blob and invalid UTF-8 entries byte-exactly", async () => {
|
||||
const blobBytes = new Uint8Array([0x89, 0x50, 0x4e, 0x47, 0x00, 0xff]);
|
||||
const invalidUtf8 = new Uint8Array([0x68, 0x69, 0xff, 0xfe, 0xc0]);
|
||||
const archive = createStoredZipArchive(
|
||||
{
|
||||
"COMPANY.md": "# Company\n",
|
||||
"blobs/4f2d1c9a": blobBytes,
|
||||
"notes/raw": invalidUtf8,
|
||||
},
|
||||
"paperclip-demo",
|
||||
);
|
||||
|
||||
await expect(readZipArchive(archive)).resolves.toEqual({
|
||||
rootPath: "paperclip-demo",
|
||||
files: {
|
||||
"COMPANY.md": "# Company\n",
|
||||
"blobs/4f2d1c9a": {
|
||||
encoding: "base64",
|
||||
data: Buffer.from(blobBytes).toString("base64"),
|
||||
contentType: "application/octet-stream",
|
||||
},
|
||||
"notes/raw": {
|
||||
encoding: "base64",
|
||||
data: Buffer.from(invalidUtf8).toString("base64"),
|
||||
contentType: "application/octet-stream",
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -36,6 +36,13 @@ secret redaction still run on the bounded result set.
|
||||
Agent detail links fetch an older selected run by ID when it is outside the
|
||||
history page, and verify that it belongs to the current company and agent.
|
||||
|
||||
Saved-run policy and parent-report lookups read only the `executionPolicy`
|
||||
value or the legacy `issueId` and `taskId` values from a run context. PostgreSQL projects
|
||||
those JSON values before it sends the row to the controller. Unused prompt and
|
||||
launch context does not travel with each policy or parent-report check. JSON
|
||||
types, task-key precedence, and company and agent identity checks are preserved.
|
||||
Each decision still reads current data; this is not an authorization cache.
|
||||
|
||||
To compare the real summary and full history queries with an earlier revision:
|
||||
|
||||
```sh
|
||||
|
||||
@@ -33,8 +33,10 @@ Explicit project policies and issue workspace settings still take precedence. A
|
||||
Projects and individual issues can set `sharedWorkspaceConcurrency` in their execution workspace policy/settings:
|
||||
|
||||
- `auto` (the default when absent): allow concurrent shared-workspace runs on `local` and `ssh` environments, and serialize runs on `sandbox` and `plugin` environments. An instance forced to Kubernetes always serializes in `auto` mode.
|
||||
- `serialize`: on `sandbox` and `plugin` environments, defer a run while another live run holds the same project workspace, using the `workspace_busy` retry path. Local and SSH folders remain concurrent, even when an existing project or issue policy requests serialization.
|
||||
- `allow`: dispatch alongside a live holder on every environment.
|
||||
- `serialize`: on `sandbox` and `plugin` environments, defer a run while another live run holds the same project workspace or the same reused shared execution workspace, using the `workspace_busy` retry path. Local and SSH folders remain concurrent, even when an existing project or issue policy requests serialization.
|
||||
- `allow`: dispatch alongside a live holder on `local` and `ssh` environments. Other environments cannot place concurrent agents in one physical shared folder, so a run with a live holder fails with `configuration_incomplete` (`shared_realization_unsupported`) instead of waiting.
|
||||
|
||||
A reused shared execution workspace follows the same rules. For example, a child task can inherit the shared execution workspace of a parent whose run is still live. In `auto` or `serialize` mode on a sandbox, the child waits for the parent run to finish and then continues automatically. A parent run that is still running but has produced no output for more than an hour still holds the folder. In that case the child fails with `configuration_incomplete` (`shared_realization_unsupported`). It does not share the folder with the parent, and it does not wait without limit.
|
||||
|
||||
Issue settings override the project policy, which overrides the default `auto`. The final execution environment determines whether workspace serialization applies; an instance forced to Kubernetes is a sandbox even if the agent normally runs locally. Local and SSH folder runs never wait for exclusive workspace ownership. Task checkout and per-agent concurrency limits still apply. When concurrency is allowed and a live holder exists, Paperclip adds the holder run and issue to the dispatched task context so agents can coordinate concurrent mutations through commits. The setting is optional JSON policy data, so existing databases require no migration.
|
||||
|
||||
|
||||
@@ -22,7 +22,9 @@ Use **Save & exit** to preserve unfinished setup. See the official
|
||||
Manage the Bot from its agent's **Runtime** settings. This shows connection
|
||||
health, routine configuration, and verification. Model selection, local paths,
|
||||
and runtime tests are managed outside Paperclip; use **Verify connection** to
|
||||
check both directions.
|
||||
check both directions. Use **Reconnect agent access** to restore the same agent's
|
||||
connection. Select **Copy code** beside the masked one-use pairing code, then
|
||||
paste it into Paperclip's authorization page. Keep it out of Bot chat.
|
||||
|
||||
Assign ordinary tasks to the agent. Read its progress, answer its question cards,
|
||||
and review its documents and files in the task thread. The Bot can initiate a
|
||||
|
||||
@@ -27,3 +27,11 @@ The importer saves available repository files without asking for repair decision
|
||||
The production dialog shows every skill by default, selects all discovered skills, and collapses individual package files. It uses one collapsed warnings disclosure and leaves Import repository available. The importer has no packaging option: new imports keep repository files together. Storybook covers omitted files, warning details, missing references, setup problems, warnings after import, and mobile review. Focused scanner/delivery/PostgreSQL tests and UI tests verify saved warnings and available bytes; browser fixtures exercise the production UI. This revision has not rerun the paid local/Daytona campaigns above.
|
||||
|
||||
Final acceptance also found and fixed duplicate saved warnings and an installed-file viewer that did not expose repository dependencies. The viewer now lists repository files and reads their saved bytes without GitHub access. Content errors for unsafe execution or secret disclosure omit the affected files with warnings; the remaining repository can still import. Database and scanner regressions verify these exclusions and file-reader company isolation.
|
||||
|
||||
## October 14: dependency read batches
|
||||
|
||||
Oversized repository imports read each Markdown dependency frontier through the existing bounded Git batch reader. The next frontier contains newly found references. The scanner retains its file and byte limits, content audits, reference order, and fallback for snapshot readers without batch support. This avoids one Git child process for each Markdown file during a source refresh.
|
||||
|
||||
The regression checks a real oversized Git repository with 64 skills, transitive references, and a reference cycle. It compares every retained file's bytes and requires four batch reads with no individual reads. A local comparison of the old and final dependency walkers on 500 Markdown files and two shared references returned identical entries: three old samples took 4.9–6.2 seconds with 502 child processes, while the new samples took 62–85 milliseconds with three batches. These measurements exclude provider execution and do not establish agent response latency.
|
||||
|
||||
The frontier uses a queue of newly added Markdown files. A regression at the 9,990-file limit retains every file, terminates a reference cycle, and bounds path visits. The earlier frontier rescan made 50,014,936 path visits in a local comparison. The queue makes 89,911 visits and retains the same output order.
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,89 @@
|
||||
# Heartbeat disposition test audit — 2026-10-12
|
||||
|
||||
Two duplicate fixture-and-recovery executions are retired. Test registrations fall from 398 to 396. Test source changes by +13/−68, net−55 lines. No execution-time or CI-time benefit is claimed.
|
||||
|
||||
The historical pre-integration proof parent was #16099 at `8e955181d8a3776acc86e4662de3c77933231a76`, branch `codex/test-audit-daytona-pack`. The complete 248-declaration, 398-runtime-case ledger and 49 helper/hook hashes are in the companion JSON evidence file. All 52 matrix declarations remain. All 245 declarations outside the keeper and the two retirements retain their source hashes.
|
||||
|
||||
## Retired and keeper map
|
||||
|
||||
| Role | Original lines | Case |
|
||||
| --- | --- | --- |
|
||||
| Retired case 202 |13446–13471| `repairs missing disposition independently of the productive diagnostic label` |
|
||||
| Retired case 207 |13710–13749| `re-enqueues recovery when the latest in-progress continuation made progress but left no live path` |
|
||||
| Keeper case 239 |15632–15706| `does not treat a productive terminal run as healthy when in-progress work has no live path` |
|
||||
|
||||
Each seeds `seedStrandedIssueFixture({status: "in_progress", runStatus: "succeeded", livenessState: "advanced"})`, creates one heartbeat service, and reconciles once. No optional fixture input differs. The keeper's extra precondition queries are reads. They confirm the source owner and the absence of active company runs and live company wakes.
|
||||
|
||||
The keeper retains its complete original checks. It receives the exact successful/continuation/escalation counters, post-reconcile issue state, two wakes, the original agent-only run count, and the conditional settlement wait. Both the agent-only and company+agent query boundaries remain. Full retry issue/task/source/ancestor identity and the absent modelProfile remain. Crash, ownership, persistence, restart, cancellation, error and distinct liveness scenarios outside this exact fixture are unchanged.
|
||||
|
||||
## Historical sequential exact-parent controls
|
||||
|
||||
| Phase | Passed | Failed | Skipped |
|
||||
| --- | --- | --- | --- |
|
||||
| baseline | 398 | 0 | 0 |
|
||||
| candidate | 396 | 0 | 0 |
|
||||
| revert | 398 | 0 | 0 |
|
||||
| mutation-source-original | 0 | 1 | 397 |
|
||||
| mutation-source-keeper | 0 | 1 | 395 |
|
||||
| mutation-counter-original | 0 | 1 | 397 |
|
||||
| mutation-counter-keeper | 0 | 1 | 395 |
|
||||
| restoration | 396 | 0 | 0 |
|
||||
|
||||
The four mutation runs select one intended case each. Their unselected skips do not count as coverage. The real recovery owner runs against isolated embedded Postgres; adapter mocks are unchanged.
|
||||
|
||||
The source mutation changes `server/src/services/recovery/service.ts:3163` from the canonical persisted context source to `issue.wrong_disposition_repair`. It fails retired case 202 at original line 13463 and the keeper at candidate line 15635, at the context source oracle.
|
||||
|
||||
The independent counter mutation adds `successfulContinuationObserved += 1` in the active queued legacy-repair branch at `server/src/services/recovery/service.ts:4513`. It fails retired case 207 at original line 13721 and the keeper at candidate line 15608, where the counter expects 0 and receives 1. Other earlier liveness checks pass before this guard.
|
||||
|
||||
Restoring the owner returns the full candidate to 396/396 with zero failures/skips. Test and owner source are then restored byte for byte to the exact parent before the final patch is applied. The process snapshot has no owned remaining test/Postgres process. No global main Postgres process is present at that snapshot. One unrelated Vitest process in another checkout remains. It is not part of this proof. No global process is terminated by this audit.
|
||||
|
||||
## Integrated revision checks
|
||||
|
||||
The counts, source hashes, matrix/declaration ledger and mutation line numbers
|
||||
below and in the companion JSON were recorded before integration. They do not
|
||||
claim a passing run or matching whole-file hashes on today's PR head.
|
||||
|
||||
The integrated code revisions are parent
|
||||
`ef04ba1592a5932d2d971e09b09467f878572d7a` and candidate
|
||||
`1daaa7496b67c9d38eb7ee4f3eec9e1a3e27cd86`. These immutable public revisions
|
||||
precede this documentation clarification; the clarification changes no tests or
|
||||
production source. Fresh static checks confirm the candidate still changes only
|
||||
+13/-68 lines in `heartbeat-process-recovery.test.ts`, and the production owner
|
||||
has identical bytes in both revisions.
|
||||
|
||||
| Integrated file | Parent SHA-256 | Candidate SHA-256 |
|
||||
| --- | --- | --- |
|
||||
| `heartbeat-process-recovery.test.ts` | `66c6fcfd0a798bc690355eef86306c3b02dead31341e14e27a27bf3f7e5ca061` | `e1d787440f7a24cde1601da41a7c2d78897f0e0b9b31c88657479332d3ff3310` |
|
||||
| `recovery/service.ts` | `6f23f16a963eb4fe743daad39bc3a51373b72799c851ac9b367ebf119c2b706c` | `6f23f16a963eb4fe743daad39bc3a51373b72799c851ac9b367ebf119c2b706c` |
|
||||
|
||||
```sh
|
||||
base=ef04ba1592a5932d2d971e09b09467f878572d7a
|
||||
candidate=1daaa7496b67c9d38eb7ee4f3eec9e1a3e27cd86
|
||||
git fetch https://github.com/paperclipai/paperclip.git "$base" "$candidate"
|
||||
git diff --check "$base" "$candidate"
|
||||
git diff --numstat "$base" "$candidate" -- server/src/__tests__/heartbeat-process-recovery.test.ts
|
||||
git show "$base":server/src/__tests__/heartbeat-process-recovery.test.ts | shasum -a 256
|
||||
git show "$candidate":server/src/__tests__/heartbeat-process-recovery.test.ts | shasum -a 256
|
||||
git diff --exit-code "$base" "$candidate" -- server/src/services/recovery/service.ts
|
||||
```
|
||||
|
||||
To validate the integrated owner, create separate isolated checkouts at these
|
||||
revisions, install the pinned dependencies and run the owner command below in
|
||||
each. Record actual current counts; do not substitute the historical 398/396
|
||||
counts. Current-head CI must validate the integrated change before merge. This
|
||||
clarification records static checks, not a new local runtime or mutation run.
|
||||
|
||||
## Reproduce historical controls
|
||||
|
||||
Use isolated PAPERCLIP_HOME, PAPERCLIP_CONFIG and TMPDIR values and the checked-in root/server Vitest configuration:
|
||||
|
||||
```sh
|
||||
node node_modules/vitest/vitest.mjs run --project @paperclipai/server \
|
||||
server/src/__tests__/heartbeat-process-recovery.test.ts --exclude '**/dist/**'
|
||||
```
|
||||
|
||||
Run baseline, candidate, full revert, each original/keeper mutation independently, then the full restored candidate. Restore source after proof. Mutation patches are described above and are never committed.
|
||||
|
||||
## Limits
|
||||
|
||||
This is a narrow test change. Local controls cover the entire owner. Repository-wide typecheck/test/build and review gates must be checked on the new PR head. No timing or broader live-product acceptance claim is made.
|
||||
@@ -0,0 +1,30 @@
|
||||
# Round 10 database schema test audit
|
||||
|
||||
This test-only change is stacked on #16075 at `3432307f95f679e20b991c6a250934c2114b7aaf`. The original matched baseline and control ran on its prior head `e86a747fc028069d2bb4d699bd814e0d82fad558`. The parent correction changes documentation only; the rebased complete owner replay passed 6/6 with no failures or skips. It removes one registered case and six net test lines. It makes no measured CI time claim.
|
||||
|
||||
| Retired case | Keeper | Preserved observations |
|
||||
| --- | --- | --- |
|
||||
| `keeps the owner principal non-null and drops the environment from the key` | `serializes the active slot on company, owner, and adapter` | Copy the exact `started_by_user_id` non-null assertion. The keeper's exact index column list already proves that the owner is present and the environment is absent. |
|
||||
|
||||
Both cases inspect the same `adapterAuthSessions` table and active index. The keeper still checks index presence, uniqueness, the exact company/owner/adapter columns, and the partial predicate. The public-session identity, claim marker, active states, secret-column exclusion, and migration SQL cases remain separate. No fixture, helper, schema, migration, or caller changes.
|
||||
|
||||
The direct owner is `packages/db/src/schema/adapter_auth_sessions.ts`. Its owner column prevents a null principal from escaping the active unique index. Local login, device login, and setup-token services use this company/owner/adapter scope. The DB project runs in the default `general-workspaces-c` CI group.
|
||||
|
||||
Complete-file command:
|
||||
|
||||
```sh
|
||||
pnpm exec vitest run packages/db/src/adapter-auth-sessions-schema.test.ts
|
||||
```
|
||||
|
||||
| Run on the exact stacked base | Passed | Failed | Skipped |
|
||||
| --- | ---: | ---: | ---: |
|
||||
| Baseline | 7 | 0 | 0 |
|
||||
| Candidate | 6 | 0 | 0 |
|
||||
| Nullability control | 5 | 1 | 0 |
|
||||
| Restored-owner candidate | 6 | 0 | 0 |
|
||||
|
||||
The deliberate control removes only `.notNull()` from `startedByUserId` in the production schema. The complete file fails only the keeper at the copied non-null assertion (`false` instead of `true`). The other five cases pass. Restore the schema before the positive replay.
|
||||
|
||||
A whole-program byte comparison proves that the only test changes are one retired statement and one exact copied assertion. Production schema bytes are restored with SHA-256 `ada8f01da2171306b97e5cb2b14b52dd53f6a7d58dd9dd51414d381c56821235`. Candidate test SHA-256 is `9719104e3f6d79d868dee36b1778ce758da8829ffc4485019cad41a128bcff6f`. The earlier independent proof at `77408fa6c3d7c916d7160760eae2144aaa0f8fe7` is preserved separately. Root review approved the keeper map before this PR.
|
||||
|
||||
Risk: the index keeper now reports both index and owner-nullability defects. An earlier index failure can stop the later assertion, but still fails the scenario. Each distinct schema and migration contract remains covered.
|
||||
@@ -0,0 +1,113 @@
|
||||
# 2026-10-12 native status corpus preservation map
|
||||
|
||||
The native status-authority corpus keeps one complete execution of its 53 real fixtures. The comparison-negative loop uses those same actual observations. It no longer creates another set of issues, runs, decisions, effects, and wakes only to change expected comparison fields.
|
||||
|
||||
The change is stacked on public PR #16076 at parent commit `9abd9b23bde1da5fa1f11bfb9ce9a0d5d4c5a8dd`. The dedicated branch is `codex/test-audit-r11-corpus`.
|
||||
|
||||
## Change and retained proof
|
||||
|
||||
| Item | Before | After |
|
||||
|---|---:|---:|
|
||||
| Full real-corpus passes in the two affected declarations | 2 | 1 |
|
||||
| Real fixture executions in those passes | 106 | 53 |
|
||||
| Corpus fixture definitions | 53 | 53 |
|
||||
| Joined contract matrix rows | 70 | 70 |
|
||||
| Negative comparison field categories | 11 | 11 |
|
||||
| Registered owner and sibling cases | 62 | 61 |
|
||||
| Corpus test source lines | 2,981 | 2,976 |
|
||||
|
||||
No production source changes. All later live-entrypoint negative controls and storage, status-lock, lineage, reviewer, child-delivery, and monitor tests remain. Those controls still run their targeted scenarios separately.
|
||||
|
||||
The first declaration at `server/src/__tests__/native-status-arbiter-corpus.test.ts:1821` keeps all real consumer execution and matrix checks. It absorbs the pure negative-comparison loop from the former declaration at line 1870. The loop body is byte-identical. The two original full passes had identical fixture lists and `executeFixture` calls. The moved loop changes expected fields and local comparison objects. It does not write to the database or change the original observations.
|
||||
|
||||
All 53 fixture behavior rows are distinct when comparing mode, given facts, and expected behavior. No fixture definitions were removed.
|
||||
|
||||
## Exact-parent verification
|
||||
|
||||
| Phase | Result |
|
||||
|---|---|
|
||||
| Baseline at the parent head | 62/62 passed |
|
||||
| Candidate | 61/61 passed |
|
||||
| Comparator owner mutation | Keeper failed inside the moved negative assertion |
|
||||
| Comparator restored to candidate bytes | 61/61 passed |
|
||||
|
||||
Mutation: remove the `reasonCode` comparison from the test-local `comparisonFailures` owner at original line 358. Correct production results still satisfy the positive comparison. The moved negative check fails with `native-mechanical-completion:reasonCode: expected [] to not deeply equal []` at mutated candidate line 1889. This is a comparator/harness-owner regression, not a production status-policy mutation. The comparator was restored byte for byte before the final full owner and sibling replay.
|
||||
|
||||
Run from `server/`:
|
||||
|
||||
```sh
|
||||
node ../node_modules/vitest/vitest.mjs run --config vitest.config.ts src/__tests__/native-status-arbiter-corpus.test.ts src/services/native-runtime/status-arbiter.test.ts
|
||||
```
|
||||
|
||||
The mutation replay selects the merged keeper with `-t 'executes all 53 fixtures, joins all 70 matrix rows'`.
|
||||
|
||||
Repo-wide typecheck, the full Vitest suite, and build were not run locally for this narrow test-only change. The draft PR checks must pass before a merge-ready handoff.
|
||||
|
||||
## Source identity and local cost
|
||||
|
||||
- Baseline corpus SHA-256: `1dffa2f852ff2a9c5c6b174cfb3ef21746b65d124e4593d00401588923bbdcf0`.
|
||||
- Candidate corpus SHA-256: `e4974c65b704ea3aac7887cddf2707f53c686578fe5c0b1b2aeab42fa10c9d38`.
|
||||
- Local fixture-test subtotals: baseline `1897.437 ms`; candidate `967.448 ms`; comparator-restored candidate `985.561 ms`.
|
||||
|
||||
These are local Vitest replay samples, not CI timings or a controlled benchmark. The evidence supports removal of the repeated pass. It does not claim a fixed CI time reduction.
|
||||
|
||||
## Declaration ledger
|
||||
|
||||
The full-file review covers the corpus test (31 declarations) and the sibling policy test (17 declarations). Each table row below records one declaration. All parameter rows stay unless the ledger says otherwise.
|
||||
|
||||
| File | Parent line | Test declaration | Mark and retained contract |
|
||||
|---|---:|---|---|
|
||||
| native-status-arbiter-corpus.test.ts | 1821 | executes all 53 fixtures in their production consumers and joins all 70 matrix rows | R: Primary real-consumer receipt owner; catches incorrect decisions/effects, missing persisted targets, replay duplication, and incomplete matrix joins. Absorbs the comparator-negative loop. |
|
||||
| native-status-arbiter-corpus.test.ts | 1870 | fails independently when any asserted field category is mutated | C: Keep every comparison-negative assertion, but use the first declaration’s 53 real observations; this declaration currently executes exactly the same fixture list a second time. |
|
||||
| native-status-arbiter-corpus.test.ts | 1900 | fails mapped fixtures when live entrypoints or owning actions are removed despite matching policy labels | R: Distinct live-entrypoint negative controls; policy labels alone must not masquerade as cancellation, attention, workspace reconciliation, rollout, or effect delivery. |
|
||||
| native-status-arbiter-corpus.test.ts | 2066 | retires a proven automatic review and applies the current successful completion exactly once | R: Automatic-review retirement must produce exactly one superseding completion and remain idempotent. |
|
||||
| native-status-arbiter-corpus.test.ts | 2081 | automatic review reconciliation preserves unread child results (%s); rows: queued, claimed, deferred_issue_execution, current_run, current_intent, consumed | R: Distinct six durable wake delivery states govern whether unread child results hold completion; preserve all rows. |
|
||||
| native-status-arbiter-corpus.test.ts | 2113 | rechecks child delivery under the status lock during automatic review reconciliation | R: A child wake arriving between initial assessment and status lock must block a stale completion commit. |
|
||||
| native-status-arbiter-corpus.test.ts | 2138 | new evidence cannot complete reconciliation before a pending child result is consumed | R: Reconciliation policy must prioritize pending child results and emit the release-checkout effect, which the storage-level sibling does not assert. |
|
||||
| native-status-arbiter-corpus.test.ts | 2146 | new-evidence reconciliation respects %s child delivery; rows: queued, consumed | R: Actual queued/consumed wake rows must select the new-evidence reconciliation path and persisted task status; preserve both rows. |
|
||||
| native-status-arbiter-corpus.test.ts | 2164 | completes a new merge run after an old CI review and bounds repeated incomplete results | R: New merge runs may retire old CI reviews, while repeated incomplete reports must terminate bounded repair without manufacturing approvals. |
|
||||
| native-status-arbiter-corpus.test.ts | 2195 | rejects wrong, missing, and duplicate criterion IDs before accepting completion | R: Completion feedback validates exact criterion ID membership/cardinality and remains read-only. |
|
||||
| native-status-arbiter-corpus.test.ts | 2206 | keeps genuine approval actionable in the finish response and in finalization | R: Genuine human approval remains pending; finish feedback escapes prompt-injection titles and rejects failed verification. |
|
||||
| native-status-arbiter-corpus.test.ts | 2231 | preserves answered cards, explicit attention, stronger authority, and later task edits | R: Six independent guard facts prevent unsafe automatic review retirement: resolved response, explicit attention, authority, later status, newer contract, failed workspace. |
|
||||
| native-status-arbiter-corpus.test.ts | 2251 | rejects an empty needs_review report with actionable feedback without inventing an approval | R: Empty needs-review reports fail with actionable feedback and leave review retirement to its owning reconciler. |
|
||||
| native-status-arbiter-corpus.test.ts | 2262 | withdraws obsolete policy reviews, restores the prior status, and is idempotent | R: Obsolete-policy cleanup restores prior status/version while retaining decision history, then becomes idempotent. |
|
||||
| native-status-arbiter-corpus.test.ts | 2276 | leaves an already %s review untouched; rows: accepted, rejected | R: Accepted and rejected interactions are both authoritative responses and must remain untouched; preserve both rows. |
|
||||
| native-status-arbiter-corpus.test.ts | 2286 | preserves real completion reviews and limits cleanup to the requested runs | R: Genuine reviews and unrelated run-scoped cards must not be retired. |
|
||||
| native-status-arbiter-corpus.test.ts | 2296 | dismisses the obsolete card without undoing a later %s status; rows: blocked, done, cancelled | R: Blocked, done, and cancelled later states have distinct cancellation/expiry behavior and must not be overwritten; preserve all rows. |
|
||||
| native-status-arbiter-corpus.test.ts | 2306 | does not restore status after a newer decision or a status change back to review | R: Changed decision pointer and a round-trip status edit independently invalidate restoration authority. |
|
||||
| native-status-arbiter-corpus.test.ts | 2321 | keeps review status when a separate request still needs a response | R: Another pending interaction retains review liveness even after obsolete-card retirement. |
|
||||
| native-status-arbiter-corpus.test.ts | 2332 | isolates a failed cleanup candidate and retries it on the next pass | R: One failed cleanup transaction must not stop other candidates; a later pass retries the failed candidate. |
|
||||
| native-status-arbiter-corpus.test.ts | 2354 | keeps committed cleanup and continues publication after a live event fails | R: Live-event publication failure must not roll back committed cleanup or prevent later publication. |
|
||||
| native-status-arbiter-corpus.test.ts | 2374 | continues native finalization when the obsolete-card lookup fails | R: Obsolete-card lookup failure must not halt native finalization. |
|
||||
| native-status-arbiter-corpus.test.ts | 2388 | preserves a later authoritative status during reconciliation | R: Reconciliation reducer preserves externally advanced blocked state and its explicit authority reason. |
|
||||
| native-status-arbiter-corpus.test.ts | 2399 | supersedes the exact committed coordinator decision and sequences preserve decisions independently of issue status versions | R: Semantic decision sequencing is independent of statusVersion changes and supersedes the exact committed coordinator decision. |
|
||||
| native-status-arbiter-corpus.test.ts | 2469 | keeps assessment lineage run-local while superseding an issue decision from another run | R: Cross-run issue decision supersession must preserve current-run assessment ancestry and durable effect payload linkage. |
|
||||
| native-status-arbiter-corpus.test.ts | 2634 | preserves an intermediate same-run assessment when the issue decision points to an older ancestor | R: An intermediate same-run assessment must not be replaced with the older issue-decision ancestor. |
|
||||
| native-status-arbiter-corpus.test.ts | 2741 | ignores historical committed finalizations superseded by a newer authoritative decision | R: Historical committed finalization must remain untouched after a newer authoritative decision wins. |
|
||||
| native-status-arbiter-corpus.test.ts | 2811 | records run-scoped superseding assessment lineage with %s predecessor; rows: none, same_run, other_run | R: No predecessor, same-run predecessor, and other-run predecessor must all preserve run-local assessment lineage; preserve all rows. |
|
||||
| native-status-arbiter-corpus.test.ts | 2893 | binds a tools-refresh continuation to its existing durable wake without a duplicate | R: Tools-refresh continuation must bind its existing wake exactly once, rather than insert a duplicate. |
|
||||
| native-status-arbiter-corpus.test.ts | 2910 | revalidates a %s monitor under the final disposition lock; rows: scheduled, cleared, replaced, reassigned | R: Scheduled, cleared, replaced, and reassigned monitor authority is rechecked under the status lock; preserve all rows. |
|
||||
| native-status-arbiter-corpus.test.ts | 2943 | fails the transaction closed for an unknown status effect | R: Unknown effect kinds fail the complete transaction closed, leaving no decision/effect/status/coordinator mutation. |
|
||||
| status-arbiter.test.ts | 47 | keeps a verified accepted Cursor plan passive without completing or replaying work | R: Accepted plan wait is passive only with verified authority and still yields to failed terminals, cancelled issues, and governance. |
|
||||
| status-arbiter.test.ts | 68 | a reviewer finishes its decision without completing rejected or still-reviewed work | R: A resolved reviewer action must preserve worker/review task status and avoid retrying the worker assignment. |
|
||||
| status-arbiter.test.ts | 76 | routes an unfinished reviewer action to bounded recovery instead of retrying the worker task | R: Pending reviewer actions require bounded reviewer recovery without generic continuation/retry. |
|
||||
| status-arbiter.test.ts | 85 | treats only the authorized Board response_wake as passive and preserves governance | R: Board response-wait authority, origin, governance, and non-response continuations select distinct policy branches. |
|
||||
| status-arbiter.test.ts | 138 | repairs unfinished response waits once using the server continuation budget | R: Unfinished response waits must use bounded server repair while preserving pause, dependency, governance, external-chat, and conversation authority. |
|
||||
| status-arbiter.test.ts | 172 | marks done only from successful finalization and complete durable evidence | R: Durable evidence and accepted low-risk policy are separate completion authorities; missing evidence alone cannot complete standard work. |
|
||||
| status-arbiter.test.ts | 245 | creates explicit liveness paths for review, continuation, cancellation, and governance | R: Reviewless needs-review reports, retry continuations, external-chat authority, run cancellation, and governance have distinct liveness/effect contracts. |
|
||||
| status-arbiter.test.ts | 379 | accepts low-risk completion claims with unrun verification caveats | R: Explicit unrun-verification caveats are permitted under accepted low-risk completion policy without treating them as failed verification. |
|
||||
| status-arbiter.test.ts | 424 | keeps failed verification with the agent and routes explicit attention to its owner | R: Failed verification overrides low-risk claim acceptance; explicit attention separately creates review authority. |
|
||||
| status-arbiter.test.ts | 485 | blocks only for a task-wide blocker with a named owner and action | R: Task-wide blockers bind named unblock ownership and send the required owner notification. |
|
||||
| status-arbiter.test.ts | 513 | waits for an explicit unblock instead of inventing another productive track | R: Current-track blockers bind explicit unblock actions without inventing a runnable alternate track; policy version is independently guarded. |
|
||||
| status-arbiter.test.ts | 554 | blocks a current-track result when a durable dependency already gates the issue | R: Existing durable dependencies override provider current-track labels without an immediate wake. |
|
||||
| status-arbiter.test.ts | 581 | lets a durable dependency override an optimistic done result | R: Durable dependency blockers also override an optimistic done report with policy claim acceptance. |
|
||||
| status-arbiter.test.ts | 598 | does not create a duplicate review after this run's review was already accepted | R: Accepted human review authority suppresses a second review card for needs-review disposition. |
|
||||
| status-arbiter.test.ts | 626 | does not create a duplicate review after this run's planning confirmation was already accepted | R: Accepted planning approval must also suppress a second card when disposition is blocked; this exercises a distinct allowed disposition. |
|
||||
| status-arbiter.test.ts | 654 | preserves authoritative terminal statuses | R: Authoritative done task status must not be overwritten or produce new liveness effects. |
|
||||
| status-arbiter.test.ts | 663 | routes each explicit request to its own reviewer | R: Mixed human/agent attention requests preserve separate reviewer routing and ownership. |
|
||||
|
||||
## History and stopping point
|
||||
|
||||
The executable corpus and comparison-negative control arrived in #12616. The corpus grew to 53 fixtures in #13038. The empty-effect forbidden-effects negative was corrected in #13266; this change keeps that correction verbatim.
|
||||
|
||||
The remaining declarations protect distinct policy, lifecycle, storage, atomicity, routing, and authority contracts. No further cuts are proposed in this lane.
|
||||
@@ -0,0 +1,432 @@
|
||||
{
|
||||
"baseSHA": "e12e8de07b7cbd0c1b37a921d6db432bbb8d32c5",
|
||||
"testPatchSHA256": "f339d62b12317218d4206eafa1434725a50ded2610285193802c6379afa44506",
|
||||
"tests": [
|
||||
{
|
||||
"file": "cli/src/__tests__/runtime-info.test.ts",
|
||||
"originalSHA256": "ab601b9fef15f75e5685d362a35750a891c0c8b7db466ff7d047010ff9e51714",
|
||||
"candidateSHA256": "a8beaa462ce1220221b6c2628116ccd3f45152e4177ecb3fb75410ac8a28e7c4"
|
||||
},
|
||||
{
|
||||
"file": "packages/adapters/codex-local/src/server/codex-auth-merge-decision.test.ts",
|
||||
"originalSHA256": "501bb3720e431a49f360d60b80e9b92184825920109858077bd5f2ae53ad26fa",
|
||||
"candidateSHA256": "7c00cd14422f2657056a7fd760b4fb5dc66c07e3abcda3abe6356edb8c29731a"
|
||||
},
|
||||
{
|
||||
"file": "packages/adapters/grok-local/src/server/grok-auth-merge-decision.test.ts",
|
||||
"originalSHA256": "4af358ecdac53c1b22b0288939565be015decaefcfa8502bcd2fadb9c8a14c52",
|
||||
"candidateSHA256": "39c4d03eeed86d16184df9173ad0df7c46a2c3eb1fe58f2a2125c965e64e8d0b"
|
||||
},
|
||||
{
|
||||
"file": "packages/adapters/codex-local/src/server/adapter-auth-promotion.test.ts",
|
||||
"originalSHA256": "19e37c4f9e470239408d3710a4ed1ca2414170d6ec83d50f3431593bda79019a",
|
||||
"candidateSHA256": "3be8594756d8d23ff28361e88c5175c4dc043d3ec08a64d802f5c9373c97070d"
|
||||
}
|
||||
],
|
||||
"owners": [
|
||||
{
|
||||
"file": "cli/src/runtime-info.ts",
|
||||
"originalSHA256": "b051153fd3553d71cadccff7d79edc85f6dc74fd87de5563fe91424f05eb90ec",
|
||||
"finalSHA256": "b051153fd3553d71cadccff7d79edc85f6dc74fd87de5563fe91424f05eb90ec",
|
||||
"productionRestored": true
|
||||
},
|
||||
{
|
||||
"file": "packages/adapters/codex-local/src/server/codex-auth-merge-decision.cjs",
|
||||
"originalSHA256": "86d7323e0eb4af87718c48efa4af28fb18b5c925ca42c91cd10337e696b45557",
|
||||
"finalSHA256": "86d7323e0eb4af87718c48efa4af28fb18b5c925ca42c91cd10337e696b45557",
|
||||
"productionRestored": true
|
||||
},
|
||||
{
|
||||
"file": "packages/adapters/codex-local/src/server/adapter-auth-promotion.ts",
|
||||
"originalSHA256": "6065e6e64c53965709acec0fd21431c1b08799bef8a9f2a9fba92f4c367a740a",
|
||||
"finalSHA256": "6065e6e64c53965709acec0fd21431c1b08799bef8a9f2a9fba92f4c367a740a",
|
||||
"productionRestored": true
|
||||
},
|
||||
{
|
||||
"file": "packages/adapters/grok-local/src/server/grok-auth-merge-decision.cjs",
|
||||
"originalSHA256": "573b115eebbb2ccf93dcbae415f1f182862f196a8d10ca3b1c3aafe5ced7ec64",
|
||||
"finalSHA256": "573b115eebbb2ccf93dcbae415f1f182862f196a8d10ca3b1c3aafe5ced7ec64",
|
||||
"productionRestored": true
|
||||
}
|
||||
],
|
||||
"completeFileRuns": [
|
||||
{
|
||||
"label": "baseline",
|
||||
"exitCode": 0,
|
||||
"passed": 177,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"files": [
|
||||
{
|
||||
"name": "packages/adapters/codex-local/src/server/adapter-auth-promotion.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 28
|
||||
},
|
||||
{
|
||||
"name": "packages/adapters/codex-local/src/server/codex-auth-cache.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 31
|
||||
},
|
||||
{
|
||||
"name": "packages/adapters/codex-local/src/server/codex-auth-copyback.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 17
|
||||
},
|
||||
{
|
||||
"name": "packages/adapters/codex-local/src/server/codex-auth-merge-decision.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 14
|
||||
},
|
||||
{
|
||||
"name": "packages/adapters/codex-local/src/server/codex-home.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 53
|
||||
},
|
||||
{
|
||||
"name": "cli/src/__tests__/runtime-info.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 3
|
||||
},
|
||||
{
|
||||
"name": "packages/adapters/grok-local/src/server/grok-auth-copyback.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 11
|
||||
},
|
||||
{
|
||||
"name": "packages/adapters/grok-local/src/server/grok-auth-merge-decision.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 11
|
||||
},
|
||||
{
|
||||
"name": "packages/adapters/grok-local/src/server/grok-home.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 9
|
||||
}
|
||||
],
|
||||
"reportSHA256": "a2a46938d83607e37c114e7b4da42068230185e787fbd08ad97101f30820acec",
|
||||
"logSHA256": "79fc48066d2f3f285d8a270b163121d73c99885c2708bc862c3ba8aa042abec0"
|
||||
},
|
||||
{
|
||||
"label": "candidate",
|
||||
"exitCode": 0,
|
||||
"passed": 170,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"files": [
|
||||
{
|
||||
"name": "packages/adapters/codex-local/src/server/adapter-auth-promotion.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 25
|
||||
},
|
||||
{
|
||||
"name": "packages/adapters/codex-local/src/server/codex-auth-cache.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 31
|
||||
},
|
||||
{
|
||||
"name": "packages/adapters/codex-local/src/server/codex-auth-copyback.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 17
|
||||
},
|
||||
{
|
||||
"name": "packages/adapters/codex-local/src/server/codex-auth-merge-decision.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 12
|
||||
},
|
||||
{
|
||||
"name": "packages/adapters/codex-local/src/server/codex-home.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 53
|
||||
},
|
||||
{
|
||||
"name": "packages/adapters/grok-local/src/server/grok-auth-copyback.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 11
|
||||
},
|
||||
{
|
||||
"name": "packages/adapters/grok-local/src/server/grok-auth-merge-decision.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 10
|
||||
},
|
||||
{
|
||||
"name": "packages/adapters/grok-local/src/server/grok-home.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 9
|
||||
},
|
||||
{
|
||||
"name": "cli/src/__tests__/runtime-info.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 2
|
||||
}
|
||||
],
|
||||
"reportSHA256": "4604c4120f3a892eda54fa9836a62e1805ee5c48fbfb4e9086eaf3ae8870c782",
|
||||
"logSHA256": "084c1048d51859ee32c514672fd0a4a0828eeea0ca2dc42bf8310d2de46e215c"
|
||||
},
|
||||
{
|
||||
"label": "revert",
|
||||
"exitCode": 0,
|
||||
"passed": 177,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"files": [
|
||||
{
|
||||
"name": "packages/adapters/codex-local/src/server/adapter-auth-promotion.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 28
|
||||
},
|
||||
{
|
||||
"name": "packages/adapters/codex-local/src/server/codex-auth-cache.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 31
|
||||
},
|
||||
{
|
||||
"name": "packages/adapters/codex-local/src/server/codex-auth-copyback.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 17
|
||||
},
|
||||
{
|
||||
"name": "packages/adapters/codex-local/src/server/codex-auth-merge-decision.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 14
|
||||
},
|
||||
{
|
||||
"name": "packages/adapters/codex-local/src/server/codex-home.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 53
|
||||
},
|
||||
{
|
||||
"name": "packages/adapters/grok-local/src/server/grok-auth-copyback.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 11
|
||||
},
|
||||
{
|
||||
"name": "packages/adapters/grok-local/src/server/grok-auth-merge-decision.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 11
|
||||
},
|
||||
{
|
||||
"name": "packages/adapters/grok-local/src/server/grok-home.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 9
|
||||
},
|
||||
{
|
||||
"name": "cli/src/__tests__/runtime-info.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 3
|
||||
}
|
||||
],
|
||||
"reportSHA256": "b60e9b8b949acb1fb603100c59bf9c36cc564858426ebe2576fae3c11a8ab3e7",
|
||||
"logSHA256": "0395a74d8c069e3a8963c297599d94655e3768ccc5c8c6f2ab108cb4c8a3b450"
|
||||
},
|
||||
{
|
||||
"label": "candidate-after-restoration",
|
||||
"exitCode": 0,
|
||||
"passed": 170,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"files": [
|
||||
{
|
||||
"name": "packages/adapters/codex-local/src/server/adapter-auth-promotion.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 25
|
||||
},
|
||||
{
|
||||
"name": "packages/adapters/codex-local/src/server/codex-auth-cache.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 31
|
||||
},
|
||||
{
|
||||
"name": "packages/adapters/codex-local/src/server/codex-auth-copyback.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 17
|
||||
},
|
||||
{
|
||||
"name": "packages/adapters/codex-local/src/server/codex-auth-merge-decision.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 12
|
||||
},
|
||||
{
|
||||
"name": "packages/adapters/codex-local/src/server/codex-home.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 53
|
||||
},
|
||||
{
|
||||
"name": "packages/adapters/grok-local/src/server/grok-auth-copyback.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 11
|
||||
},
|
||||
{
|
||||
"name": "packages/adapters/grok-local/src/server/grok-auth-merge-decision.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 10
|
||||
},
|
||||
{
|
||||
"name": "packages/adapters/grok-local/src/server/grok-home.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 9
|
||||
},
|
||||
{
|
||||
"name": "cli/src/__tests__/runtime-info.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 2
|
||||
}
|
||||
],
|
||||
"reportSHA256": "d2d363ab57d607633f12d75eaea17265010e834c7d92bed588334a39e6550867",
|
||||
"logSHA256": "21cfea7bd04b674fccbe2226aebfba9b19dc12b022df995d7c35e779122c01bf"
|
||||
}
|
||||
],
|
||||
"mutations": [
|
||||
{
|
||||
"label": "mutation-runtime-write",
|
||||
"exitCode": 1,
|
||||
"passed": 0,
|
||||
"failed": 1,
|
||||
"skipped": 1,
|
||||
"reportSHA256": "5271aa251ce2c804eaea9fb345854c61674247c5cf91aaf3f2c043f1177fde69",
|
||||
"logSHA256": "68f6c2f446ef0f1717f1f676f65e999657f9455954279890566a2a777dade6da",
|
||||
"originalSHA256": "b051153fd3553d71cadccff7d79edc85f6dc74fd87de5563fe91424f05eb90ec",
|
||||
"mutatedSHA256": "4bab7a0eb48f9ec37c7912640c544a460e498ecc806200fb086c7f9c23c24490",
|
||||
"owner": "cli/src/runtime-info.ts",
|
||||
"keeper": "runtime info does not remove runtime info owned by a replacement process",
|
||||
"mutationId": "runtime-write",
|
||||
"assertion": "AssertionError: expected null to deeply equal { schemaVersion: 1, \u2026(6) }",
|
||||
"edit": {
|
||||
"from": " fs.renameSync(temporaryPath, filePath);",
|
||||
"to": "omit the atomic rename statement"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "mutation-codex-default-absent",
|
||||
"exitCode": 1,
|
||||
"passed": 0,
|
||||
"failed": 1,
|
||||
"skipped": 11,
|
||||
"reportSHA256": "5441f2d038e120fdd62f40fbf0adad3711f5bee66ac214a2f188ad90b798a22a",
|
||||
"logSHA256": "d52cd9f252f1f9ebf4da23f86cacd9682fc7137aef7ec64d311c14074aed2226",
|
||||
"originalSHA256": "86d7323e0eb4af87718c48efa4af28fb18b5c925ca42c91cd10337e696b45557",
|
||||
"mutatedSHA256": "c2140ce41b07a007adc6232b1db6ee308db14f5adfd7e31aa17d509970afa97f",
|
||||
"owner": "packages/adapters/codex-local/src/server/codex-auth-merge-decision.cjs",
|
||||
"keeper": "codex-auth-merge-decision predicate seed mode the leading positional --seed-if-dest-absent flag is parsed before the two path arguments; a default two-path call never enters seed mode",
|
||||
"mutationId": "codex-default-absent",
|
||||
"assertion": "AssertionError: expected 10 to be 20 // Object.is equality",
|
||||
"edit": {
|
||||
"from": " seedIfDestAbsent &&",
|
||||
"to": " true &&"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "mutation-codex-seed-absent",
|
||||
"exitCode": 1,
|
||||
"passed": 0,
|
||||
"failed": 1,
|
||||
"skipped": 11,
|
||||
"reportSHA256": "0784aed1b34cb2dfa13d7c93ac10d5ef8a9f38da153eebce234c762fab6cb628",
|
||||
"logSHA256": "02e7b7367bdecc722e3a57bffb8974dee0afc2c0304f23dcea76db3a13ce8ad6",
|
||||
"originalSHA256": "86d7323e0eb4af87718c48efa4af28fb18b5c925ca42c91cd10337e696b45557",
|
||||
"mutatedSHA256": "867730de34972c627b235a1499aee126ab428dd899098e5b1d30d450dd764113",
|
||||
"owner": "packages/adapters/codex-local/src/server/codex-auth-merge-decision.cjs",
|
||||
"keeper": "codex-auth-merge-decision predicate seed mode the leading positional --seed-if-dest-absent flag is parsed before the two path arguments; a default two-path call never enters seed mode",
|
||||
"mutationId": "codex-seed-absent",
|
||||
"assertion": "AssertionError: expected 20 to be 10 // Object.is equality",
|
||||
"edit": {
|
||||
"from": " return sourceIsImplausible ? IMPLAUSIBLE_LAST_REFRESH : USE_SOURCE;",
|
||||
"to": " return KEEP_DESTINATION;"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "mutation-grok-iso-expiry",
|
||||
"exitCode": 1,
|
||||
"passed": 0,
|
||||
"failed": 1,
|
||||
"skipped": 9,
|
||||
"reportSHA256": "3aa14c8f3dc9a4720743926fb0f62601aba8a7cc862d154064ab32b17cc3e2fd",
|
||||
"logSHA256": "f7835d91b6d8bbdd039ca56cc83205de798b82b4ce791b33a546a2d7cde7bb25",
|
||||
"originalSHA256": "573b115eebbb2ccf93dcbae415f1f182862f196a8d10ca3b1c3aafe5ced7ec64",
|
||||
"mutatedSHA256": "20a815272eff6fefe592f09e55d9d690ca3eee41e98145b4447fcdac9828d856",
|
||||
"owner": "packages/adapters/grok-local/src/server/grok-auth-merge-decision.cjs",
|
||||
"keeper": "grok-auth-merge-decision predicate reads an ISO-8601 expiry, an epoch-seconds expiry, and an epoch-milliseconds expiry",
|
||||
"mutationId": "grok-iso-expiry",
|
||||
"assertion": "AssertionError: ISO-8601: expected 20 to be 10 // Object.is equality",
|
||||
"edit": {
|
||||
"from": " const ms = Date.parse(raw);",
|
||||
"to": " const ms = 0;"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "mutation-promotion-company-home",
|
||||
"exitCode": 1,
|
||||
"passed": 0,
|
||||
"failed": 1,
|
||||
"skipped": 24,
|
||||
"reportSHA256": "aca6aa3dc842e1f1ba1c956b245393de4d2ee993d8da156b960b0af6fd69c2bc",
|
||||
"logSHA256": "0fa22f697fbc4b042cb58ad1efe6d8db0459a6fe129e584b4666cfc421cad8f8",
|
||||
"originalSHA256": "6065e6e64c53965709acec0fd21431c1b08799bef8a9f2a9fba92f4c367a740a",
|
||||
"mutatedSHA256": "cf54fc5ca674868f4b98f8af0700800153837fc5db26066aec99eb530127f06e",
|
||||
"owner": "packages/adapters/codex-local/src/server/adapter-auth-promotion.ts",
|
||||
"keeper": "device-login credential promotion a user login seeds this account's own home and the company default home",
|
||||
"mutationId": "promotion-company-home",
|
||||
"assertion": "AssertionError: expected 'wrong-account' to be 'acct-42' // Object.is equality",
|
||||
"edit": {
|
||||
"from": " sourceBytes: authBytes,\n destinationPath: companyHomeAuthPath,",
|
||||
"to": " sourceBytes: Buffer.from(JSON.stringify({ ...JSON.parse(authBytes.toString()), tokens: { ...JSON.parse(authBytes.toString()).tokens, account_id: \"wrong-account\" } })),\n destinationPath: companyHomeAuthPath,"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "mutation-promotion-account-id",
|
||||
"exitCode": 1,
|
||||
"passed": 0,
|
||||
"failed": 1,
|
||||
"skipped": 24,
|
||||
"reportSHA256": "73d41f793829a226a0aee3cbb12b66702353f9d83bbc7e3d146f72486f193a43",
|
||||
"logSHA256": "4deb6470827ab1cd43e3761b43ec4f73b16dbd8a6941bbf92b50c7f527d7b549",
|
||||
"originalSHA256": "6065e6e64c53965709acec0fd21431c1b08799bef8a9f2a9fba92f4c367a740a",
|
||||
"mutatedSHA256": "d1b3f413f0c9e5a0c2f3fd57e37f4eaf38254884c4adb894b8e2fb03605272c0",
|
||||
"owner": "packages/adapters/codex-local/src/server/adapter-auth-promotion.ts",
|
||||
"keeper": "device-login credential promotion a user login seeds this account's own home and the company default home",
|
||||
"mutationId": "promotion-account-id",
|
||||
"assertion": "AssertionError: expected 'wrong-account' to be 'acct-42' // Object.is equality",
|
||||
"edit": {
|
||||
"from": " outcome: accountHomeOutcome === \"written\" ? \"promoted\" : \"kept\",\n accountId,",
|
||||
"to": " outcome: accountHomeOutcome === \"written\" ? \"promoted\" : \"kept\",\n accountId: \"wrong-account\","
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "mutation-promotion-account-home",
|
||||
"exitCode": 1,
|
||||
"passed": 0,
|
||||
"failed": 1,
|
||||
"skipped": 24,
|
||||
"reportSHA256": "2202e3a9350c8cccbbf880e728055c5703c594d1480a62525858842db7052f25",
|
||||
"logSHA256": "daa89ab14e44be704e8a6926bda850d0c2e214bf602cff161bc00c5b3fa930b7",
|
||||
"originalSHA256": "6065e6e64c53965709acec0fd21431c1b08799bef8a9f2a9fba92f4c367a740a",
|
||||
"mutatedSHA256": "b03b3fac62ac26b179b13505268fbfd59cbf63213f10da87835f33fd5c54843d",
|
||||
"owner": "packages/adapters/codex-local/src/server/adapter-auth-promotion.ts",
|
||||
"keeper": "device-login credential promotion a user login seeds this account's own home and the company default home",
|
||||
"mutationId": "promotion-account-home",
|
||||
"assertion": "AssertionError: expected 'wrong-home' to be the exact independently resolved account-home path",
|
||||
"edit": {
|
||||
"from": " outcome: accountHomeOutcome === \"written\" ? \"promoted\" : \"kept\",\n accountId,\n accountHomeDir,",
|
||||
"to": " outcome: accountHomeOutcome === \"written\" ? \"promoted\" : \"kept\",\n accountId,\n accountHomeDir: \"wrong-home\","
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "mutation-promotion-created-receipt",
|
||||
"exitCode": 1,
|
||||
"passed": 0,
|
||||
"failed": 1,
|
||||
"skipped": 24,
|
||||
"reportSHA256": "3ded03074b1f22efa84f940fbc17a91465b4f65434010e0b2b8ccc9fb16a3fa8",
|
||||
"logSHA256": "c12316bc00a075f589b03d2b6686120d39cd8ec89763d22599546801fcf4900f",
|
||||
"originalSHA256": "6065e6e64c53965709acec0fd21431c1b08799bef8a9f2a9fba92f4c367a740a",
|
||||
"mutatedSHA256": "3d13658dcc9bfeab21ace2d5f44d30bd6490e73bdacb18810ab3415822bc4956",
|
||||
"owner": "packages/adapters/codex-local/src/server/adapter-auth-promotion.ts",
|
||||
"keeper": "device-login credential promotion a user login seeds this account's own home and the company default home",
|
||||
"mutationId": "promotion-created-receipt",
|
||||
"assertion": "AssertionError: expected false to be true // Object.is equality",
|
||||
"edit": {
|
||||
"from": " outcome: accountHomeOutcome === \"written\" ? \"promoted\" : \"kept\",\n accountId,\n accountHomeDir,\n accountHomeCreated,",
|
||||
"to": " outcome: accountHomeOutcome === \"written\" ? \"promoted\" : \"kept\",\n accountId,\n accountHomeDir,\n accountHomeCreated: false,"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
# Test audit R12: runtime and credential owner coverage
|
||||
|
||||
Date: 2026-10-12. Base: `e12e8de07b7cbd0c1b37a921d6db432bbb8d32c5`, the head of [R11](https://github.com/paperclipai/paperclip/pull/16078). Branch: `codex/test-audit-r12-runtime-auth`.
|
||||
|
||||
This change removes **seven redundant registered executions and 76 net test lines** across four files. It changes no production code. Each retired case repeats an existing owner invocation. Three result assertions move into the existing stronger first-login case. No wall-time improvement is inferred from these counts.
|
||||
|
||||
## Exact retirement map
|
||||
|
||||
| File | Retired exact case | Retained keeper and observation |
|
||||
| --- | --- | --- |
|
||||
| `cli/src/__tests__/runtime-info.test.ts` | `writes and reads the selected runtime endpoint` | `does not remove runtime info owned by a replacement process`: same fresh fixture, write and exact read; wrong-PID preservation and matching-PID removal also remain. |
|
||||
| `packages/adapters/codex-local/src/server/codex-auth-merge-decision.test.ts` | `default mode keeps destination when destination is absent (host-default fail-closed)` | `the leading positional --seed-if-dest-absent flag is parsed before the two path arguments; a default two-path call never enters seed mode`: identical subscription bytes and absent destination, actual subprocess, exit 20. |
|
||||
| Same Codex decision file | `seed mode uses source when destination is absent and source is a usable subscription credential` | Same leading-flag keeper: identical opt-in call, actual subprocess, exit 10. |
|
||||
| `packages/adapters/grok-local/src/server/grok-auth-merge-decision.test.ts` | `uses the source when the identity matches and the source expiry is later` | `reads an ISO-8601 expiry, an epoch-seconds expiry, and an epoch-milliseconds expiry`: ISO row retains identical source/destination credential shape, markers and later-expiry relation through actual files and subprocess; all encodings remain. |
|
||||
| `packages/adapters/codex-local/src/server/adapter-auth-promotion.test.ts` | `promotion returns the account id and the account home path` | `a user login seeds this account's own home and the company default home`: identical fresh-root input and callbacks. Exact account ID and account-home path assertions move unchanged into this keeper. |
|
||||
| Same promotion file | `promotion reports accountHomeCreated true for a first login of an account` | Same first-login keeper gains the exact true receipt. Repeat-login and concurrent-created receipts remain separate. |
|
||||
| Same promotion file | `promotion seeds the company default home when it holds no usable credential` | Same first-login keeper already reads the company default home's actual account ID and also reads the account home, checks promoted outcome and forbids instance-global writes. |
|
||||
|
||||
The retired invocations comprise one runtime-info write/read scenario, two Codex decision subprocesses, one Grok decision subprocess and three fresh-login promotions. Table registration and internal case execution are unchanged in the keepers. This is reduced duplicate execution, not only shorter test setup.
|
||||
|
||||
Net test lines: runtime-info 6; Codex decision 17; Grok decision 7; promotion 46, including five added assertion lines. Total: 81 deletions and five additions. The evidence files are excluded from those savings.
|
||||
|
||||
## Preserved contracts
|
||||
|
||||
The runtime file's malformed-input and process-ownership guards remain. Both decision suites retain identity isolation, unusable credentials, strict freshness and ties, exact clock bounds and encoding rejection. Promotion retains readiness, user-initiated/sole-owner gates, company isolation, account separation, repeat and concurrent creation, persistence failures, symlink replacement and secret redaction. No API, schema, migration, platform, lifecycle or security contract is retired.
|
||||
|
||||
## Replay on the exact stacked base
|
||||
|
||||
Nine complete existing files ran through the repository's real Vitest project configuration with isolated home, config, instance ID and temporary paths. The four owner files contain 56 original or 49 candidate cases. Five unchanged auth-cache, copyback and home siblings contain 121 cases.
|
||||
|
||||
| Phase | Passed | Failed | Skipped |
|
||||
| --- | ---: | ---: | ---: |
|
||||
| Original baseline | 177 | 0 | 0 |
|
||||
| Candidate | 170 | 0 | 0 |
|
||||
| Reverted original tests | 177 | 0 | 0 |
|
||||
| Candidate after owner restoration | 170 | 0 | 0 |
|
||||
|
||||
Run counts overlap and must not be added. Source-only filtering excludes build output. Existing pinned external dependencies are read-only; workspace dependency links point into this managed checkout. The initial discovery export was not used as PR qualification.
|
||||
|
||||
## Owner mutation controls
|
||||
|
||||
Eight deliberate changes to the real production owners each failed exactly one retained keeper at its intended assertion. Each owner was restored byte for byte in `finally` before the next run.
|
||||
|
||||
| Deliberate owner regression | Failed observation |
|
||||
| --- | --- |
|
||||
| Omit atomic runtime-file publication | Exact persisted runtime object: null instead of the written object. |
|
||||
| Seed an absent destination without the Codex opt-in flag | Default call: exit 10 instead of 20. |
|
||||
| Keep an absent destination despite the Codex opt-in flag | Seed call: exit 20 instead of 10. |
|
||||
| Erase the decoded Grok ISO expiry | ISO row: exit 20 instead of 10. |
|
||||
| Write the wrong identity to the company default home | Actual stored account ID differs. |
|
||||
| Return the wrong account ID after real promotion | Migrated result account ID differs. |
|
||||
| Return the wrong account-home path after real promotion | Migrated exact result path differs. |
|
||||
| Report false after first account-home creation | Migrated creation receipt is false instead of true. |
|
||||
|
||||
Name-filtered mutation runs skip the unrelated cases in their complete owner file. Those intentional filter skips are separate from the four complete-file controls, which have zero skips. The harness counts one failed case, rather than assuming Vitest's nested suite count equals one. No timeout, mock result, fixture receipt or setup error supplies a mutation failure.
|
||||
|
||||
[The adjacent controls record](2026-10-12-test-audit-r12-runtime-auth-controls.json) retains exact original/candidate test hashes, restored owner hashes, run/log digests, production edits and actual failing keeper assertions. Compile, build and current-head CI/review results are reported separately on the draft PR.
|
||||
@@ -0,0 +1,93 @@
|
||||
# 2026-10-12 Git credential proof ownership map
|
||||
|
||||
The Git credential owner now holds all 14 existing redaction input/output assertions. The workspace suite no longer repeats that direct helper contract through a compatibility re-export. Runtime workspace code already imports the canonical helper directly, so the obsolete heartbeat import/re-export shim can be removed.
|
||||
|
||||
Parent: public PR #16079 at `2e17a5ed43ecb0002f7f0e2fe5c1017f35d7ffab`. Branch: `codex/test-audit-r13-git-credentials`.
|
||||
|
||||
## Scope and retained contract
|
||||
|
||||
| Item | Before | After |
|
||||
|---|---:|---:|
|
||||
| Direct redaction input/output assertions | 14 | 14 |
|
||||
| Direct redaction helper calls | 14 | 14 |
|
||||
| Registered keeper/workspace cases | 206 | 201 |
|
||||
| Test source lines in the changed files | 3,705 | 3,687 |
|
||||
| Obsolete heartbeat shim source lines | 6 | 0 |
|
||||
|
||||
The net reduction is 18 test source lines and six production shim lines. This is proof ownership and seam cleanup. It does not remove helper execution or establish a CI time reduction.
|
||||
|
||||
Removed workspace declarations at parent lines 949–986 preserve their complete bodies inside the four existing keeper declarations at `server/src/__tests__/git-credentials.test.ts:282`. Their five wrappers and the heartbeat import are removed. The six-line import/comment/re-export block at `server/src/services/heartbeat.ts:323–328` is the only production change.
|
||||
|
||||
All original input/output pairs were compared as a multiset after resolving the local string constants. Both sides contain exactly 14 pairs and have this canonical SHA-256: `78ff3b460616782e2380217c22ba00dbe757203a9e34d1c38d1ea294a4c5a9e0`.
|
||||
|
||||
## Assertion relocation map
|
||||
|
||||
| Original file and assertion line | Candidate keeper assertion line | Protected case |
|
||||
|---|---:|---|
|
||||
| git-credentials.test.ts:284 | 284 | HTTPS userinfo |
|
||||
| git-credentials.test.ts:290 | 296 | SSH userinfo |
|
||||
| git-credentials.test.ts:293 | 299 | scp-style remote remains unchanged |
|
||||
| git-credentials.test.ts:299 | 311 | URL query with token and reference |
|
||||
| git-credentials.test.ts:302 | 314 | arbitrary query parameter name |
|
||||
| git-credentials.test.ts:308 | 326 | credential-free error text |
|
||||
| heartbeat-workspace-session.test.ts:951 | 287 | quoted HTTPS userinfo in a Git error |
|
||||
| heartbeat-workspace-session.test.ts:957 | 290 | bare username and multiple URLs |
|
||||
| heartbeat-workspace-session.test.ts:963 | 302 | SSH and git+ssh userinfo in one error |
|
||||
| heartbeat-workspace-session.test.ts:966 | 305 | scp-style remote with surrounding text |
|
||||
| heartbeat-workspace-session.test.ts:972 | 317 | quoted query in a Git error |
|
||||
| heartbeat-workspace-session.test.ts:975 | 320 | query with trailing error text |
|
||||
| heartbeat-workspace-session.test.ts:982 | 328 | credential-free URL error |
|
||||
| heartbeat-workspace-session.test.ts:984 | 330 | plain text with no URL |
|
||||
|
||||
## Scoped declaration ledger
|
||||
|
||||
| Parent declaration | Mark | Keeper and retained contract |
|
||||
|---|---|---|
|
||||
| git-credentials.test.ts:283 — masks URL userinfo | R | Keeps HTTPS userinfo and absorbs quoted errors, bare usernames, and multiple URLs. |
|
||||
| git-credentials.test.ts:289 — non-HTTP userinfo and scp remotes | R | Keeps SSH/scp cases and absorbs git+ssh and surrounding-message cases. |
|
||||
| git-credentials.test.ts:298 — complete query masking | R | Keeps arbitrary query keys and absorbs quote/trailing-message boundaries. |
|
||||
| git-credentials.test.ts:307 — credential-free text | R | Keeps plain errors and absorbs credential-free URL/text examples. |
|
||||
| heartbeat-workspace-session.test.ts:950 — URL userinfo | C | Move its unchanged assertion into the existing userinfo keeper. |
|
||||
| heartbeat-workspace-session.test.ts:956 — bare usernames and multiple URLs | C | Move its unchanged assertion into the existing userinfo keeper. |
|
||||
| heartbeat-workspace-session.test.ts:962 — non-HTTP userinfo and scp remotes | C | Move both unchanged assertions into the non-HTTP keeper. |
|
||||
| heartbeat-workspace-session.test.ts:971 — complete query masking | C | Move both unchanged assertions into the query keeper. |
|
||||
| heartbeat-workspace-session.test.ts:980 — credential-free text | C | Move both unchanged assertions and their local constants into the plain-text keeper. |
|
||||
| heartbeat.ts:323–328 — scrubber re-export shim | D | No runtime importer remains through heartbeat. Workspace code uses the canonical Git credential owner. |
|
||||
|
||||
Other keeper and workspace declarations stay unchanged. This is a scoped ledger, not a claim that all 206 cases were deletion candidates.
|
||||
|
||||
## Production callers and history
|
||||
|
||||
The only production callers are in `server/src/services/heartbeat/workspaces.ts`: import at line 47 and calls at lines 602, 3545, and 3553. These callers already import `scrubGitCredentialText` from `git-credentials.ts`; their code stays unchanged. Repository search found no other heartbeat re-export consumer after the workspace test import was removed.
|
||||
|
||||
#10719 introduced the workspace redaction proof. #10720 established the Git credential owner. #10722 removed a duplicate implementation and retained the heartbeat re-export so older imports, including the workspace tests, still worked. The canonical implementation and its production callers now remain; the obsolete test-only import path is removed.
|
||||
|
||||
## Exact-parent verification
|
||||
|
||||
| Phase | Result |
|
||||
|---|---|
|
||||
| Keeper/workspace baseline | 206/206 passed |
|
||||
| Candidate | 201/201 passed |
|
||||
| Production owner mutation | 24 passed; two intended keeper failures |
|
||||
| Production owner restored byte for byte | 201/201 passed |
|
||||
| Real managed-checkout caller sibling | 19/19 passed |
|
||||
|
||||
Mutation: change the userinfo mask regex from `/gi` to `/i` in `server/src/services/git-credentials.ts:111`. The helper leaks credentials in later URLs. The keeper fails in the two migrated multi-URL assertions at candidate lines 290 and 302, whose assertions finish at lines 292 and 304. The production helper was restored to its exact parent bytes before the final replay.
|
||||
|
||||
Run from `server/`:
|
||||
|
||||
```sh
|
||||
node ../node_modules/vitest/vitest.mjs run --config vitest.config.ts src/__tests__/git-credentials.test.ts src/__tests__/heartbeat-workspace-session.test.ts
|
||||
node ../node_modules/vitest/vitest.mjs run --config vitest.config.ts src/__tests__/heartbeat-managed-clone-credentials.test.ts
|
||||
```
|
||||
|
||||
Repo-wide typecheck, the full Vitest suite, and build were not run locally for this narrow owner consolidation. Draft PR checks must pass before a merge-ready handoff.
|
||||
|
||||
## Source hashes
|
||||
|
||||
| File | Parent SHA-256 | Candidate SHA-256 |
|
||||
|---|---|---|
|
||||
| server/src/__tests__/git-credentials.test.ts | `e236377145742b8074be8d61ff11b50812815436c5d188133f95475cd731384d` | `29e12200d45e8a17098bcc8571d82fc2ea3f68422b7cc04271a79b52b4f32ae0` |
|
||||
| server/src/__tests__/heartbeat-workspace-session.test.ts | `ad26f3a88c25da94502889fd3f0f158b81bd1bed03332880a383a45437703761` | `93480b2a883bb0ad075cbf143abe302225ddfd01e333431999c95e378cd8a6c3` |
|
||||
| server/src/services/heartbeat.ts | `0fb791d721262d024ef2935b3045f4a5489adfa5853d2d54dab15c639d26fe54` | `9ac217e97e5319c850924f083df32be43df11f33f8970ff8efb4a5f776a0c1d9` |
|
||||
| server/src/services/git-credentials.ts | `0e8bc7031cc7000db3d9828eb84fbd2c22d19657bfcdc5e287f95cc01e05934f` | `0e8bc7031cc7000db3d9828eb84fbd2c22d19657bfcdc5e287f95cc01e05934f` |
|
||||
@@ -0,0 +1,62 @@
|
||||
# Environment runtime test audit — 2026-10-12
|
||||
|
||||
Parent: #16083 (`codex/test-audit-r14-browser`), exact head
|
||||
`1113d4c9eaa49311c9b269c96b79bbae06d42e25`.
|
||||
|
||||
## Change and keeper
|
||||
|
||||
`server/src/__tests__/environment-runtime.test.ts:1405–1420` repeats the local
|
||||
projectless acquisition already executed by the lifecycle test at1371. Both
|
||||
use the same `seedEnvironment()` call, runtime, suite hooks and acquisition
|
||||
input. The seed/acquire statements are AST-identical. Both tests originated
|
||||
in `70679a33216` (Add sandbox environment support, #4415).
|
||||
|
||||
Move the unique `lease.executionWorkspaceId` null assertion into the keeper
|
||||
at1383. Keep the exact `leaseContext` equality, which already checks its two
|
||||
null fields. Every original keeper statement remains unchanged and ordered.
|
||||
The keeper also releases the lease and checks the durable released row.
|
||||
|
||||
One file: +2/-17 test lines, net15 fewer lines. One registered case and one
|
||||
redundant seed/acquisition/setup/cleanup cycle disappear (162→161 cases).
|
||||
No production behavior changes. Provider, SSH, company access, secret
|
||||
resolution/redaction, timeout precedence, session and recovery cases remain.
|
||||
|
||||
## Exact-parent proof
|
||||
|
||||
| Phase | Passed | Failed | Filtered/pending |
|
||||
|---|---|---|---|
|
||||
| Full baseline | 162 | 0 | 0 |
|
||||
| Full candidate | 161 | 0 | 0 |
|
||||
| Unmutated keeper control | 1 | 0 | 160 |
|
||||
| Production mutation, intended keeper | 0 | 1 | 160 |
|
||||
| Owner restored, full candidate | 161 | 0 | 0 |
|
||||
| All source reverted, full parent | 162 | 0 | 0 |
|
||||
|
||||
Proof-only production mutation at `environment-runtime.ts:4047`: acquisition
|
||||
returns `lease: { ...lease, executionWorkspaceId: lease.executionWorkspaceId
|
||||
?? input.environment.id }`. This real return-mapping fault leaves context and
|
||||
DB setup intact. The relocated assertion at1383:49 rejects the environment
|
||||
UUID because a projectless lease must return null. Production bytes were
|
||||
restored before the full candidate replay. The mutation is not in this PR.
|
||||
|
||||
The first reverted run had a suite-level startup failure (3 pure tests passed,
|
||||
159 DB cases pending, no assertion failure). JSON-only output omitted the
|
||||
hook diagnostic. An unchanged-source rerun with the default reporter passed
|
||||
162/162. The failed attempt remains in the temporary receipt. No CI speedup
|
||||
is claimed from the single local samples.
|
||||
|
||||
## Hashes and receipts
|
||||
|
||||
- Parent test SHA-256: `a7370481526c91044a020cf0e56a5ab4f27a7289c6ee8bcf94e414d7b70ab35a`.
|
||||
- Candidate test SHA-256: `39069f6d8261886b9c9521a7e3e5026051d90287b5e14c471d589fde384832e7`.
|
||||
- Production owner SHA-256: `77da04770ef8e87dd868f90a65c10ae2322a95ad1d8d78e73facb1be3443c0f8`.
|
||||
- Identical seed/acquisition AST SHA-256: `d25af395dc9775474276cefbedd2d736ddfca7c57263db5543c603e52b6f96d3`.
|
||||
|
||||
Full read: 7,223 lines, 100 declarations, 162 cases, two suites and four hooks.
|
||||
The full ledger, case mapping, patch, preservation proof and JSON/log receipts
|
||||
are in `/private/tmp/test-audit-environment-runtime/`.
|
||||
|
||||
Local verification uses the full owner with the unchanged server Vitest
|
||||
configuration. Full repository test/build preflight is deferred to isolated
|
||||
CI because this audit worktree shares dependency symlinks and preflight
|
||||
rewrites workspace package links. CI must pass before a green handoff.
|
||||
@@ -0,0 +1,97 @@
|
||||
{
|
||||
"parentPR": 16086,
|
||||
"parentBranch": "codex/test-audit-r15-environment-runtime",
|
||||
"parentHead": "c0414ac02e625a1e635857895b74581c37201500",
|
||||
"result": "PROVEN",
|
||||
"registrationsBefore": 399,
|
||||
"registrationsAfter": 398,
|
||||
"declarationsBefore": 249,
|
||||
"declarationsAfter": 248,
|
||||
"retiredCase": "heartbeat orphaned process recovery re-enqueues continuation for stranded in-progress work with no active run",
|
||||
"keeper": "heartbeat orphaned process recovery re-enqueues stranded in-progress work after a failed/process_lost run before escalating",
|
||||
"deletedTestLOC": 31,
|
||||
"movedAssertionLOC": 5,
|
||||
"netTestLOCDelta": -26,
|
||||
"candidateTestSHA256": "645fd53b52e513e97c83f1e074dc1bded0749be18fb086138d154c19ea18d1d6",
|
||||
"parentSourceHashes": {
|
||||
"server/src/__tests__/heartbeat-process-recovery.test.ts": "bf7c888eaba44a56d12823bb948026d5db44f2249a75a6cf083343edbd7c0673",
|
||||
"server/src/services/heartbeat/retries.ts": "9f29feb6d986f281cbfd849e0152f49cf56e18974c6df1bc801010dcce4c877a",
|
||||
"server/src/services/heartbeat.ts": "9ac217e97e5319c850924f083df32be43df11f33f8970ff8efb4a5f776a0c1d9",
|
||||
"server/src/services/recovery/service.ts": "c414df876e7df64e701a752513db8e5cf7365589294d50da0e1396788a9207db"
|
||||
},
|
||||
"sourceRestoredBeforeBranchCreation": true,
|
||||
"controls": [
|
||||
{
|
||||
"phase": "baseline",
|
||||
"exitCode": 0,
|
||||
"tests": 399,
|
||||
"passed": 399,
|
||||
"failed": 0,
|
||||
"pending": 0,
|
||||
"failures": [],
|
||||
"ownerSHA256": "9f29feb6d986f281cbfd849e0152f49cf56e18974c6df1bc801010dcce4c877a",
|
||||
"testSHA256": "bf7c888eaba44a56d12823bb948026d5db44f2249a75a6cf083343edbd7c0673"
|
||||
},
|
||||
{
|
||||
"phase": "candidate",
|
||||
"exitCode": 0,
|
||||
"tests": 398,
|
||||
"passed": 398,
|
||||
"failed": 0,
|
||||
"pending": 0,
|
||||
"failures": [],
|
||||
"ownerSHA256": "9f29feb6d986f281cbfd849e0152f49cf56e18974c6df1bc801010dcce4c877a",
|
||||
"testSHA256": "645fd53b52e513e97c83f1e074dc1bded0749be18fb086138d154c19ea18d1d6"
|
||||
},
|
||||
{
|
||||
"phase": "revert",
|
||||
"exitCode": 0,
|
||||
"tests": 399,
|
||||
"passed": 399,
|
||||
"failed": 0,
|
||||
"pending": 0,
|
||||
"failures": [],
|
||||
"ownerSHA256": "9f29feb6d986f281cbfd849e0152f49cf56e18974c6df1bc801010dcce4c877a",
|
||||
"testSHA256": "bf7c888eaba44a56d12823bb948026d5db44f2249a75a6cf083343edbd7c0673"
|
||||
},
|
||||
{
|
||||
"phase": "mutation-keeper",
|
||||
"exitCode": 1,
|
||||
"tests": 398,
|
||||
"passed": 0,
|
||||
"failed": 1,
|
||||
"pending": 397,
|
||||
"failures": [
|
||||
{
|
||||
"name": "heartbeat orphaned process recovery re-enqueues stranded in-progress work after a failed/process_lost run before escalating",
|
||||
"messages": [
|
||||
"AssertionError: expected { \u2026(78) } to match object { status: 'scheduled_retry', \u2026(1) }\n(84 matching properties omitted from actual)\n at Proxy.<anonymous> (file://<dependency-checkout>/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:2050:10)\n at Proxy.<anonymous> (file://<dependency-checkout>/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:1944:14)\n at Proxy.methodWrapper (file://<dependency-checkout>/node_modules/.pnpm/chai@6.3.0/node_modules/chai/index.js:1737:25)\n at server/src/__tests__/heartbeat-process-recovery.test.ts:10386:24\n at processTicksAndRejections (node:internal/process/task_queues:104:5)\n at file://<dependency-checkout>/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
],
|
||||
"ownerSHA256": "cff836de7a98e47e845ad7f7393e4c98fcfea3fecb0ba5bdb9fcc92fc9673c84",
|
||||
"testSHA256": "645fd53b52e513e97c83f1e074dc1bded0749be18fb086138d154c19ea18d1d6"
|
||||
},
|
||||
{
|
||||
"phase": "restoration",
|
||||
"exitCode": 0,
|
||||
"tests": 398,
|
||||
"passed": 398,
|
||||
"failed": 0,
|
||||
"pending": 0,
|
||||
"failures": [],
|
||||
"ownerSHA256": "9f29feb6d986f281cbfd849e0152f49cf56e18974c6df1bc801010dcce4c877a",
|
||||
"testSHA256": "645fd53b52e513e97c83f1e074dc1bded0749be18fb086138d154c19ea18d1d6"
|
||||
}
|
||||
],
|
||||
"temporaryMutation": {
|
||||
"owner": "server/src/services/heartbeat/retries.ts",
|
||||
"line": 1049,
|
||||
"before": "scheduledRetryAttempt: schedule.attempt",
|
||||
"after": "scheduledRetryAttempt: schedule.attempt + 1",
|
||||
"keeperAssertionLine": 10386,
|
||||
"selection": "Only exact failed/process_lost keeper selected; all other cases are unselected.",
|
||||
"expectedAttempt": 1,
|
||||
"observedAttempt": 2
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
# Heartbeat recovery test audit — 2026-10-12
|
||||
|
||||
Parent: #16086 (`codex/test-audit-r15-environment-runtime`), exact head
|
||||
`c0414ac02e625a1e635857895b74581c37201500`.
|
||||
|
||||
## Change and keeper
|
||||
|
||||
The standalone `re-enqueues continuation for stranded in-progress work with no active run`
|
||||
case at `heartbeat-process-recovery.test.ts:11192–11221` repeats the existing
|
||||
`re-enqueues stranded in-progress work after a failed/process_lost run before escalating`
|
||||
table row at 10360.
|
||||
|
||||
Both call `seedStrandedIssueFixture` with `status: in_progress` and
|
||||
`runStatus: failed`. The standalone test omits `runErrorCode`; the helper at 1132–1136
|
||||
persists `process_lost` as its default. The table supplies that same value.
|
||||
Every other supplied argument, default, and owner action matches. Generated
|
||||
record IDs vary between independent fixture runs.
|
||||
|
||||
Move five unique assertion lines into the keeper: a truthy retry ID and
|
||||
`{ status: scheduled_retry, scheduledRetryAttempt: 1 }`. Existing keeper checks
|
||||
retain zero dispatch, one continuation, no escalation, exact issue IDs, two
|
||||
agent runs, `transient_failure`, and absent `modelProfile`. The keeper also
|
||||
checks source task/run binding, no recovery children, and eventual settlement.
|
||||
The failed/adapter_failed and timed_out/adapter_timed_out rows remain and gain
|
||||
the durable retry assertions.
|
||||
|
||||
One test file: +5/−31 lines, net 26 fewer test lines. One registered execution
|
||||
is retired (399→398). This is execution retirement, with no production change.
|
||||
Crash/restart, ownership, cancellation, persistence, retry-budget, and failure
|
||||
isolation contracts remain. No CI time saving is claimed from local samples.
|
||||
|
||||
## Exact-parent sequential proof
|
||||
|
||||
| Phase | Passed | Failed | Filtered/pending |
|
||||
|---|---|---|---|
|
||||
| Full baseline | 399 | 0 | 0 |
|
||||
| Full candidate | 398 | 0 | 0 |
|
||||
| Full revert | 399 | 0 | 0 |
|
||||
| Temporary production mutation, exact keeper | 0 | 1 | 397 |
|
||||
| Owner restored, full candidate | 398 | 0 | 0 |
|
||||
|
||||
The mutation changes the real scheduler write at `heartbeat/retries.ts:1049`
|
||||
from `schedule.attempt` to `schedule.attempt + 1`. The exact keeper fails at
|
||||
the moved retry-state assertion, candidate line 10386, expecting attempt 1 and receiving 2. Only that keeper is
|
||||
selected; other cases are filtered. The persisted attempt feeds durable
|
||||
failure-retry accounting in `execution-recovery-attempt.ts:40–49`.
|
||||
The recovery/scheduler owner is not mocked. The mutation is absent from this PR.
|
||||
After restoring the owner, all 398 candidate cases pass. Both source files were
|
||||
then restored byte-for-byte and the checkout was clean before branch creation.
|
||||
The final patch is the exact candidate bytes that passed restoration.
|
||||
|
||||
Runtime-title comparison removes only the standalone registration and adds
|
||||
no cases. The original full-file ledger contains 249 declarations / 399 runtime
|
||||
cases; the candidate has 248 / 398. All declarations were reviewed. Near-overlaps
|
||||
with different queued wakes, timer claims, continuation ancestry, or crash points
|
||||
were retained.
|
||||
|
||||
```sh
|
||||
PAPERCLIP_HOME=/private/tmp/r16-hbr/h \
|
||||
PAPERCLIP_CONFIG=/private/tmp/r16-hbr/h/config.json \
|
||||
PAPERCLIP_INSTANCE_ID=heartbeat-recovery-audit TMPDIR=/private/tmp/r16-hbr/t NODE_ENV=test \
|
||||
node node_modules/vitest/vitest.mjs run --project @paperclipai/server \
|
||||
server/src/__tests__/heartbeat-process-recovery.test.ts --exclude '**/dist/**'
|
||||
```
|
||||
|
||||
Full repository typecheck/build/test preflight is delegated to isolated CI,
|
||||
as in the parent audit. The local worktree uses shared external dependency
|
||||
symlinks, and preflight rewrites workspace links. Every CI gate must pass
|
||||
before a green handoff. The full owner uses the checked-in server configuration
|
||||
and its real embedded Postgres.
|
||||
|
||||
## Hashes and receipts
|
||||
|
||||
- Parent test SHA-256: `bf7c888eaba44a56d12823bb948026d5db44f2249a75a6cf083343edbd7c0673`.
|
||||
- Candidate test SHA-256: `645fd53b52e513e97c83f1e074dc1bded0749be18fb086138d154c19ea18d1d6`.
|
||||
- Restored production retry owner SHA-256: `9f29feb6d986f281cbfd849e0152f49cf56e18974c6df1bc801010dcce4c877a`.
|
||||
|
||||
Machine receipts are in `2026-10-12-test-audit-r16-heartbeat-recovery-controls.json`.
|
||||
Full JSON/log output, patch, exact keeper map, and whole-file ledger are in
|
||||
`/private/tmp/r16-heartbeat-recovery/`. The earlier read-only discovery is in
|
||||
`/private/tmp/heartbeat-recovery-full-audit/`. This parent replay uses fresh
|
||||
sequential controls; it does not reuse the earlier parent proof.
|
||||
|
||||
Model: OpenAI `gpt-6.1-sol`; the host does not expose its context-window size.
|
||||
@@ -0,0 +1,41 @@
|
||||
# IssueDetail test audit — 2026-10-12
|
||||
|
||||
Parent: #16088, `codex/test-audit-r16-heartbeat-recovery`, exact head
|
||||
`a454638931ee8a2e40347aef1ab4fbf17d8acf9f`.
|
||||
|
||||
## Retained contracts
|
||||
|
||||
- The empty-subtask keeper retains the default task thread checks after the
|
||||
first flush, and default file-viewer/plan-query checks after the second.
|
||||
Its explicit empty list matches the shared beforeEach default.
|
||||
- The first-task properties-button keeper uses the same first-task input.
|
||||
It now checks closePanel before the toggle, then still proves opt-in opening.
|
||||
- Three repeated renders disappear: 140→137 cases, 109→106 declarations,
|
||||
+14/-57 test lines (43 fewer). All 17 parameterized declarations remain.
|
||||
The full ledger and AST proof remain in temporary receipts, not this PR.
|
||||
|
||||
## Exact-parent proof
|
||||
|
||||
| Full owner phase | Passed | Failed |
|
||||
|---|---|---|
|
||||
| Baseline | 140 | 0 |
|
||||
| Candidate | 137 | 0 |
|
||||
| Reverted test | 140 | 0 |
|
||||
| Default thread forced to legacy | 108 | 29 |
|
||||
| File viewer forced on | 136 | 1 |
|
||||
| Plan panel forced to render/query | 136 | 1 |
|
||||
| Panel close paths removed | 135 | 2 |
|
||||
| Production restored, candidate | 137 | 0 |
|
||||
|
||||
Each production mutation fails its intended moved keeper assertion at lines
|
||||
2463, 2470, 2473 or 4299. Each owner restoration is byte-for-byte. No cases
|
||||
are skipped. `pnpm check:token-gates`, UI typecheck and diff-check pass.
|
||||
The normal command from ui is `pnpm exec vitest run src/pages/IssueDetail.test.tsx`.
|
||||
|
||||
Parent test SHA-256: `06b026c4bd296848011d1cc30f89711453a9db0c1e4c743fa22ae653b3e942d7`.
|
||||
Candidate SHA-256: `530b6046ce0c15ece4304bc49f711af6fc95ebd62ef5b0aa0515b96ce2d94995`.
|
||||
Restored owner SHA-256: `17b28ad871c2f00fa2d1153d50f151ebd0bed68c85d5a0f2a50164a2f1a612b2`.
|
||||
Receipts: `/private/tmp/test-audit-r17-issue-detail-replay/receipt.json`.
|
||||
No production change is included. No CI speedup is claimed from local samples.
|
||||
Full repository preflight stays in isolated CI because local dependency links
|
||||
are shared; it would rewrite those links. CI must pass before green handoff.
|
||||
@@ -0,0 +1,530 @@
|
||||
{
|
||||
"audit": {
|
||||
"file": "ui/src/components/AgentConfigForm.render.test.tsx",
|
||||
"base": "e3effbb9e5c66b838f67fd487987c8bf1007e413",
|
||||
"originalSha256": "57282ae3afe8c55ac118f3a658152d8df500a87b15383c8f6b0530a7fdcfb8a0",
|
||||
"candidateSha256": "132112f3d2bb74d0844673a39ce31ffca1306e0b82d9846f3e0cafaf83e81708",
|
||||
"allOtherProgramAstUnchanged": true,
|
||||
"allOtherSourceBytesUnchanged": true,
|
||||
"newHelpers": 0,
|
||||
"registeredInvocationsRemoved": 4,
|
||||
"rootRendersRemoved": 4,
|
||||
"netTestLinesRemoved": 44,
|
||||
"migrations": [
|
||||
{
|
||||
"retired": "keeps secret access out of the main Configuration content",
|
||||
"keeper": "hides the environment override when Local is the only configured environment",
|
||||
"exactSetupStatements": 2,
|
||||
"sameEnclosingHooks": true,
|
||||
"exactCleanupStatements": 0,
|
||||
"migratedGuards": [
|
||||
"expect(result.container.textContent).not.toContain(\"Secret access\");"
|
||||
],
|
||||
"exactDuplicateGuardAlreadyKept": [],
|
||||
"registeredInvocationsRemoved": 1,
|
||||
"rootRendersRemoved": 1
|
||||
},
|
||||
{
|
||||
"retired": "starts a login session for the effective sandbox and shows the code and the authentication URL",
|
||||
"keeper": "shows a Cancel affordance while a login is active and cancels the session",
|
||||
"exactSetupStatements": 5,
|
||||
"sameEnclosingHooks": true,
|
||||
"exactCleanupStatements": 0,
|
||||
"migratedGuards": [
|
||||
"expect(mockAgentsApi.startAdapterAuthLogin).toHaveBeenCalledWith(\"company-1\", \"codex_local\", {\n environmentId: \"sandbox-1\",\n });",
|
||||
"expect(result.container.textContent).toContain(\"WXYZ-1234\");",
|
||||
"expect(result.container.textContent).toContain(\"https://auth.example.test/device\");"
|
||||
],
|
||||
"exactDuplicateGuardAlreadyKept": [],
|
||||
"registeredInvocationsRemoved": 1,
|
||||
"rootRendersRemoved": 1
|
||||
},
|
||||
{
|
||||
"retired": "shows the authorization URL and a browser-code input for a Claude sandbox",
|
||||
"keeper": "cancels an active Claude login and returns to its start state",
|
||||
"exactSetupStatements": 6,
|
||||
"sameEnclosingHooks": true,
|
||||
"exactCleanupStatements": 0,
|
||||
"migratedGuards": [
|
||||
"expect(mockAgentsApi.startClaudeSetupTokenLogin).toHaveBeenCalledWith(\"company-1\", {\n environmentId: \"sandbox-1\",\n });",
|
||||
"expect(result.container.textContent).toContain(\"https://claude.example.test/authorize\");",
|
||||
"expect(\n result.container.querySelector('input[aria-label=\"Browser code\"]'),\n ).toBeTruthy();",
|
||||
"expect(result.container.textContent).not.toContain(\"not encrypted\");"
|
||||
],
|
||||
"exactDuplicateGuardAlreadyKept": [],
|
||||
"registeredInvocationsRemoved": 1,
|
||||
"rootRendersRemoved": 1
|
||||
},
|
||||
{
|
||||
"retired": "keeps the non-path ACP controls visible when the policy hides the engine choice",
|
||||
"keeper": "hides the host path and execution-engine fields for claude_local when the policy is on",
|
||||
"exactSetupStatements": 6,
|
||||
"sameEnclosingHooks": true,
|
||||
"exactCleanupStatements": 0,
|
||||
"migratedGuards": [
|
||||
"expect(labels).toContain(\"ACP session mode\");",
|
||||
"expect(labels).toContain(\"ACP non-interactive permissions\");"
|
||||
],
|
||||
"exactDuplicateGuardAlreadyKept": [],
|
||||
"registeredInvocationsRemoved": 1,
|
||||
"rootRendersRemoved": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"verifierSha256": "084bdbc359e510397ef64daeb24e259efbc62c8b5d2c56d3e09d7f2534f155aa",
|
||||
"mutationVerifierSha256": "ca8463047109d38a447d93fb94a19bb8efe9b1df440e0abf91ab31a8c0a358a2",
|
||||
"runs": [
|
||||
{
|
||||
"kind": "baseline",
|
||||
"total": 99,
|
||||
"passed": 99,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"jsonSha256": "16a733e7e1de263ce88f1fbd89b94d4844aab7b6e7eca1fd670899fd670e263f",
|
||||
"logSha256": "3f6f04966d8971e70a782681fccde2afd1aee5099fd8f376197109ed2babd2e5"
|
||||
},
|
||||
{
|
||||
"kind": "candidate",
|
||||
"total": 95,
|
||||
"passed": 95,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"jsonSha256": "7fdabb69061f6d6f072c17224832171a225ac9a992d53c94d050c277eb467120",
|
||||
"logSha256": "2717b82c2589f41dad5d9e926a7a37dd4fd79594acc1e9e6d9614a89ae2b5841"
|
||||
}
|
||||
],
|
||||
"mutations": [
|
||||
{
|
||||
"slug": "secrets",
|
||||
"owner": "ui/src/components/AgentConfigForm.tsx",
|
||||
"sourceSha256": "bf999102f39bfc762747ce5d598e1e6ec2f926ac5fb28de55fa1baf5493f28b1",
|
||||
"title": "hides the environment override when Local is the only configured environment",
|
||||
"mutation": {
|
||||
"before": "if (!isCreate && props.content === \"secrets\")",
|
||||
"after": "if (!isCreate && (props.content === \"secrets\" || props.content === undefined))",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(result.container.textContent).not.toContain(\"Secret access\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "24cf0c3e870ddc964fe327426491a4bbdfde043206191df578686ffb089d2f8f",
|
||||
"logSha256": "10c8a0e3b2aafe33ab63fce0881fdf2b066d1cee507ccc589db6076701da4161",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "a9af939b306874f9bc7ef93c6954f3a234aafbb252c14672097aa33732c86f90",
|
||||
"logSha256": "7fa30fef5ccdfa2cb797df92c4b207dff1eac29c99b9dcefa7a977278a4c3593",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected 'Secret accessSecrets this agent can r\u2026' not to contain 'Secret access'\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/AgentConfigForm.render.test.tsx:822:46\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "codex-company",
|
||||
"owner": "ui/src/components/AgentConfigForm.tsx",
|
||||
"sourceSha256": "bf999102f39bfc762747ce5d598e1e6ec2f926ac5fb28de55fa1baf5493f28b1",
|
||||
"title": "shows a Cancel affordance while a login is active and cancels the session",
|
||||
"mutation": {
|
||||
"before": "agentsApi.startAdapterAuthLogin(companyId, adapterType, { environmentId, aiConnection })",
|
||||
"after": "agentsApi.startAdapterAuthLogin(\"wrong-company\", adapterType, { environmentId, aiConnection })",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(mockAgentsApi.startAdapterAuthLogin).toHaveBeenCalledWith(",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "fabccb095c86b4151cb80e0446d83e60074a4da76e7f0a36d4fef0246a483696",
|
||||
"logSha256": "3397bb075079467542110406669cb26177cbbcdee8c6e6c56a5f52ccaaafd30f",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "332cf3fce408da458c33289abaf343fbf76ffedc68d37ee532a5c43ffc09f93e",
|
||||
"logSha256": "81892e052e638ba655789fcac2b9bf95b243d1bd628c86a72053ebd7c596a432",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected \"vi.fn()\" to be called with arguments: [ Array(3) ]\n\nReceived:\n\n 1st vi.fn() call:\n\n [\n- \"company-1\",\n+ \"wrong-company\",\n \"codex_local\",\n {\n+ \"aiConnection\": undefined,\n \"environmentId\": \"sandbox-1\",\n },\n ]\n\n\nNumber of calls: 1\n\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:2233:10)\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:1944:14)\n at Proxy.methodWrapper (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/chai@6.3.0/node_modules/chai/index.js:1737:25)\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/AgentConfigForm.render.test.tsx:1593:49\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "codex-adapter",
|
||||
"owner": "ui/src/components/AgentConfigForm.tsx",
|
||||
"sourceSha256": "bf999102f39bfc762747ce5d598e1e6ec2f926ac5fb28de55fa1baf5493f28b1",
|
||||
"title": "shows a Cancel affordance while a login is active and cancels the session",
|
||||
"mutation": {
|
||||
"before": "agentsApi.startAdapterAuthLogin(companyId, adapterType, { environmentId, aiConnection })",
|
||||
"after": "agentsApi.startAdapterAuthLogin(companyId, \"wrong-adapter\", { environmentId, aiConnection })",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(mockAgentsApi.startAdapterAuthLogin).toHaveBeenCalledWith(",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "3acb41404a916f7bc11b1ff698bfbaaa22017c67835907e59283b7b1df5ea07c",
|
||||
"logSha256": "6530c744b0788868f9123b062307dfd1fac3f40740e193943a81da360fb19f3a",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "b3cbd3bfee156e965bed6924beefc3f0e6009785f3dcade569f03b88fd5cba55",
|
||||
"logSha256": "90eeb1ecbbce2406915a5123c24d1311016fc1fe3d878af795781da3c352a071",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected \"vi.fn()\" to be called with arguments: [ Array(3) ]\n\nReceived:\n\n 1st vi.fn() call:\n\n [\n \"company-1\",\n- \"codex_local\",\n+ \"wrong-adapter\",\n {\n+ \"aiConnection\": undefined,\n \"environmentId\": \"sandbox-1\",\n },\n ]\n\n\nNumber of calls: 1\n\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:2233:10)\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:1944:14)\n at Proxy.methodWrapper (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/chai@6.3.0/node_modules/chai/index.js:1737:25)\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/AgentConfigForm.render.test.tsx:1593:49\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "codex-environment",
|
||||
"owner": "ui/src/components/AgentConfigForm.tsx",
|
||||
"sourceSha256": "bf999102f39bfc762747ce5d598e1e6ec2f926ac5fb28de55fa1baf5493f28b1",
|
||||
"title": "shows a Cancel affordance while a login is active and cancels the session",
|
||||
"mutation": {
|
||||
"before": "agentsApi.startAdapterAuthLogin(companyId, adapterType, { environmentId, aiConnection })",
|
||||
"after": "agentsApi.startAdapterAuthLogin(companyId, adapterType, { environmentId: \"wrong-sandbox\", aiConnection })",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(mockAgentsApi.startAdapterAuthLogin).toHaveBeenCalledWith(",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "3afd47d7705415ceb4ad8b7ce1415bd61b0b202d65732881660d75e75910c536",
|
||||
"logSha256": "874b11b544fc038fba5e9ff57b156229acbbefb1db8410bf1bebc6794d1e5f20",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "2750457c4f575d786dade8a250f50520e08b1e351c95d2562900a06ffc9ab769",
|
||||
"logSha256": "845ff3e01a9b6640496b2f895ca31e169639a65e3bf8e94bb3a383026e232b8b",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected \"vi.fn()\" to be called with arguments: [ Array(3) ]\n\nReceived:\n\n 1st vi.fn() call:\n\n [\n \"company-1\",\n \"codex_local\",\n {\n- \"environmentId\": \"sandbox-1\",\n+ \"aiConnection\": undefined,\n+ \"environmentId\": \"wrong-sandbox\",\n },\n ]\n\n\nNumber of calls: 1\n\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:2233:10)\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:1944:14)\n at Proxy.methodWrapper (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/chai@6.3.0/node_modules/chai/index.js:1737:25)\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/AgentConfigForm.render.test.tsx:1593:49\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "codex-code",
|
||||
"owner": "ui/src/components/AgentConfigForm.tsx",
|
||||
"sourceSha256": "bf999102f39bfc762747ce5d598e1e6ec2f926ac5fb28de55fa1baf5493f28b1",
|
||||
"title": "shows a Cancel affordance while a login is active and cancels the session",
|
||||
"mutation": {
|
||||
"before": "{prompt.code}</span>",
|
||||
"after": "{\"missing code\"}</span>",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(result.container.textContent).toContain(\"WXYZ-1234\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "f985ab64892d06589b60759cb68183f52c9128056b79c93e69880cb5ff8c3ad1",
|
||||
"logSha256": "dba2f7e6b14ed30859608119e88ac17f20c3c6de3ad93727a357d3860dc5a592",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "3a7ecc1e9c5e40c93c8e92f9e3930a4d0a01a2f84f01ffed53541c3403be4737",
|
||||
"logSha256": "77c403024242dedc9cfa765484486337c97a35133cea348ed4ec57caf26a760d",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected 'IdentityNameTitleReports toChoose man\u2026' to contain 'WXYZ-1234'\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/AgentConfigForm.render.test.tsx:1596:42\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "codex-url",
|
||||
"owner": "ui/src/components/AgentConfigForm.tsx",
|
||||
"sourceSha256": "bf999102f39bfc762747ce5d598e1e6ec2f926ac5fb28de55fa1baf5493f28b1",
|
||||
"title": "shows a Cancel affordance while a login is active and cancels the session",
|
||||
"mutation": {
|
||||
"before": "{prompt.url}</span>",
|
||||
"after": "{\"missing url\"}</span>",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(result.container.textContent).toContain(\"https://auth.example.test/device\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "0a11ca18e53fda28ea9a2956ee7254ab1b9f40f32f772b530df169adb06569b9",
|
||||
"logSha256": "1772bbd6667cd1f32383f0671a186bc263054ef434de07933bac4feda1e3d4b6",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "3cca5f95b518a31622ebf3f17758c4617fa40476623210da56eee539c5a1efb6",
|
||||
"logSha256": "1bac45eb7f9b150cdc6a99067d62e588baeca3af41d148fe897d0a0fa5949332",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected 'IdentityNameTitleReports toChoose man\u2026' to contain 'https://auth.example.test/device'\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/AgentConfigForm.render.test.tsx:1597:42\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "claude-company",
|
||||
"owner": "ui/src/components/AgentConfigForm.tsx",
|
||||
"sourceSha256": "bf999102f39bfc762747ce5d598e1e6ec2f926ac5fb28de55fa1baf5493f28b1",
|
||||
"title": "cancels an active Claude login and returns to its start state",
|
||||
"mutation": {
|
||||
"before": "agentsApi.startClaudeSetupTokenLogin(companyId, {",
|
||||
"after": "agentsApi.startClaudeSetupTokenLogin(\"wrong-company\", {",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(mockAgentsApi.startClaudeSetupTokenLogin).toHaveBeenCalledWith(",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "40ec576f564d239009569ca0033715f58f5b255f76ef22da20b134c2e490218f",
|
||||
"logSha256": "075d5fe2d62f1b80f60d63e0ce37e540fffdf2e666b01a21740264e6d4075478",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "0bf3dff32509866e86a80d67029ee81a1437d335045a91cb6cdf7f6ce59b5982",
|
||||
"logSha256": "7ae4dcd73616fa424d373204986a05e798f573b5659daef4ac58bc6f7b9d9fdf",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected \"vi.fn()\" to be called with arguments: [ 'company-1', \u2026(1) ]\n\nReceived:\n\n 1st vi.fn() call:\n\n [\n- \"company-1\",\n+ \"wrong-company\",\n {\n+ \"aiConnection\": undefined,\n \"environmentId\": \"sandbox-1\",\n },\n ]\n\n\nNumber of calls: 1\n\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:2233:10)\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:1944:14)\n at Proxy.methodWrapper (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/chai@6.3.0/node_modules/chai/index.js:1737:25)\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/AgentConfigForm.render.test.tsx:2782:54\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "claude-environment",
|
||||
"owner": "ui/src/components/AgentConfigForm.tsx",
|
||||
"sourceSha256": "bf999102f39bfc762747ce5d598e1e6ec2f926ac5fb28de55fa1baf5493f28b1",
|
||||
"title": "cancels an active Claude login and returns to its start state",
|
||||
"mutation": {
|
||||
"before": "agentsApi.startClaudeSetupTokenLogin(companyId, {\n environmentId,",
|
||||
"after": "agentsApi.startClaudeSetupTokenLogin(companyId, {\n environmentId: \"wrong-sandbox\",",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(mockAgentsApi.startClaudeSetupTokenLogin).toHaveBeenCalledWith(",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "4250b6cc6d66dc4df5753f403ef6894ceacdbc94bbf7812c5788ae143201d617",
|
||||
"logSha256": "b76c385cbee9d1e26130b8e0c8c5f61fb2b31523e2ca65e2fbbf7303037ff179",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "7dfc3e5efa6eeb0c719d717b901b31fca6ca4a5cff1eb817382fa932a90f983b",
|
||||
"logSha256": "56c3a19a6f86d4cc69918c47afd81bc4b4d887f788c135c7b956ea4fc3c0903c",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected \"vi.fn()\" to be called with arguments: [ 'company-1', \u2026(1) ]\n\nReceived:\n\n 1st vi.fn() call:\n\n [\n \"company-1\",\n {\n- \"environmentId\": \"sandbox-1\",\n+ \"aiConnection\": undefined,\n+ \"environmentId\": \"wrong-sandbox\",\n },\n ]\n\n\nNumber of calls: 1\n\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:2233:10)\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:1944:14)\n at Proxy.methodWrapper (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/chai@6.3.0/node_modules/chai/index.js:1737:25)\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/AgentConfigForm.render.test.tsx:2782:54\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "claude-url",
|
||||
"owner": "ui/src/components/AgentConfigForm.tsx",
|
||||
"sourceSha256": "bf999102f39bfc762747ce5d598e1e6ec2f926ac5fb28de55fa1baf5493f28b1",
|
||||
"title": "cancels an active Claude login and returns to its start state",
|
||||
"mutation": {
|
||||
"before": "{authorizationUrl}</span>",
|
||||
"after": "{\"missing authorization url\"}</span>",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(result.container.textContent).toContain(\"https://claude.example.test/authorize\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "8ee00e28a8630374d9bfe8c85d96a44121121377b89b7f845ee4b32d659833f5",
|
||||
"logSha256": "35255166875e6184b0a10b1abc4c6f42a281d4217eeac6ba2d1bbda83620aaf9",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "b2aca78cbef836af30a95188def37939d9ea2d0af743392abe804ae1bf118605",
|
||||
"logSha256": "bb383cfabd0dc16036f31324b47ad392159a9eb7db75c622e2c2e132c2d1ee63",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected 'IdentityNameTitleReports toChoose man\u2026' to contain 'https://claude.example.test/authorize'\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/AgentConfigForm.render.test.tsx:2787:42\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "claude-input",
|
||||
"owner": "ui/src/components/AgentConfigForm.tsx",
|
||||
"sourceSha256": "bf999102f39bfc762747ce5d598e1e6ec2f926ac5fb28de55fa1baf5493f28b1",
|
||||
"title": "cancels an active Claude login and returns to its start state",
|
||||
"mutation": {
|
||||
"before": "aria-label=\"Browser code\"",
|
||||
"after": "aria-label=\"Missing browser input\"",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "result.container.querySelector('input[aria-label=\"Browser code\"]')",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "cf8cb1ded0e9999bb966c94c1c38aa7a147d217a06ff4ebe647c4f03ed3e550f",
|
||||
"logSha256": "dc8c2389ba9b411989fc0d60a27e489829b21de1001c94b908555c337dfc685e",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "1bffa0d67d82af2e69b851eea8a1d4b2c319f85cad4b9b9fdf36dc95c143bde5",
|
||||
"logSha256": "13f2b561842f8803f084be9723c7042abf5c0be74b625c99effb180f0c57dc4d",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected null to be truthy\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/AgentConfigForm.render.test.tsx:2790:7\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "claude-advisory",
|
||||
"owner": "ui/src/components/AgentConfigForm.tsx",
|
||||
"sourceSha256": "bf999102f39bfc762747ce5d598e1e6ec2f926ac5fb28de55fa1baf5493f28b1",
|
||||
"title": "cancels an active Claude login and returns to its start state",
|
||||
"mutation": {
|
||||
"before": "{transportInsecure && (",
|
||||
"after": "{true && (",
|
||||
"replacementCount": 2
|
||||
},
|
||||
"intendedGuard": "expect(result.container.textContent).not.toContain(\"not encrypted\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "ce03b65cc51ee03992fec6dfa438798f57053b914aca0cb56a791a43817a04b7",
|
||||
"logSha256": "1e6753c737dd67dafe5f8cc4f7ec40be3be0875a4b97f0668e8d457a31462d4f",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "7f3ed2737dd31b0caf900567545c59d50c2cbf9aca876fd35080f13c87fb8757",
|
||||
"logSha256": "aca8606f2a3f8176814074b81c913ec3f702e44141cd2131e28c14de2ce695c7",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected 'IdentityNameTitleReports toChoose man\u2026' not to contain 'not encrypted'\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/AgentConfigForm.render.test.tsx:2793:46\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "acp-mode",
|
||||
"owner": "ui/src/adapters/claude-local/config-fields.tsx",
|
||||
"sourceSha256": "c7e5aa4093bf30d31d5d3b1de092abe767965b7c79143965f92f8c250bf916f6",
|
||||
"title": "hides the host path and execution-engine fields for claude_local when the policy is on",
|
||||
"mutation": {
|
||||
"before": "label=\"ACP session mode\"",
|
||||
"after": "label=\"Missing ACP mode\"",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(labels).toContain(\"ACP session mode\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "f6011ba4b3d6f34b47bf64dd76424cfb674b81a6663a58df2dd3994b9f87fca7",
|
||||
"logSha256": "0174f7e7bcb488d93a15306214bb579be7049bfba08e3a048c3183f79360b6b0",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "294e714633d60e3121afe528b1c461d32bf13e4407cbfbd0da2581fc6d22f1ad",
|
||||
"logSha256": "90a2ade05e125113eabeb530edec54a30e21dabd097407bb285139f4d87a35af",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected [ Array(17) ] to include 'ACP session mode'\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:2077:15)\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:1944:14)\n at Proxy.methodWrapper (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/chai@6.3.0/node_modules/chai/index.js:1737:25)\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/AgentConfigForm.render.test.tsx:3599:20\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "acp-permissions",
|
||||
"owner": "ui/src/adapters/claude-local/config-fields.tsx",
|
||||
"sourceSha256": "c7e5aa4093bf30d31d5d3b1de092abe767965b7c79143965f92f8c250bf916f6",
|
||||
"title": "hides the host path and execution-engine fields for claude_local when the policy is on",
|
||||
"mutation": {
|
||||
"before": "label=\"ACP non-interactive permissions\"",
|
||||
"after": "label=\"Missing ACP permissions\"",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(labels).toContain(\"ACP non-interactive permissions\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "f859cc875b6f5c83be73f63cf9122d2fe928ad225c6d815a9ae29f6fed365766",
|
||||
"logSha256": "06269344f536044578526368812f6c89c02f8208b9258beb773d14043859720b",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "b8b76b1c053101b532aec230f5356cbea28900d0c40fb012e3a8cc9b93a1ff2d",
|
||||
"logSha256": "590f6908806038ca072a41f61516323dcba661886afbab66c0e1cf280c596060",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected [ Array(17) ] to include 'ACP non-interactive permissions'\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:2077:15)\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:1944:14)\n at Proxy.methodWrapper (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/chai@6.3.0/node_modules/chai/index.js:1737:25)\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/AgentConfigForm.render.test.tsx:3600:20\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"priorEvidenceUnchanged": [
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appboundary-controls.json",
|
||||
"sha256": "bad49e7bc92dea919df6b980bfa45e7452984cf31a6fd4655b355ba0444ff9a6"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appboundary.md",
|
||||
"sha256": "cd6f173584db0d485004af6f85b1ce78fa65b19d8c6ef582b061f0d232c6c1ed"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appdetail-controls.json",
|
||||
"sha256": "7906fde0d62e14a7511b5cf45f864c9386a4c377922333eefc7f7e703c832f6a"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appdetail.md",
|
||||
"sha256": "715f23cd27502c92d0f5d1b83b91bcac03f254c73ab63b44181ae76939805229"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-attachments-controls.json",
|
||||
"sha256": "c4ff66a3226e1edafd286cad0ca45c9445795b46944cf70d606c59a754913f3a"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-attachments.md",
|
||||
"sha256": "d38715393c95306d10e871a5a2c9a32f105fa1452871cd7ad030d86dbbdb7416"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-controls.json",
|
||||
"sha256": "0d445f6f066032f2d9cd724525a8d7d2290246cbfeee1f6ab4b44818467af2a7"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-route-controls.json",
|
||||
"sha256": "0a72a7770ec749f2c0507a74d395e65d70b722d0b9d2a767a2c066a67ed46382"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-route.md",
|
||||
"sha256": "9b5e1543163d6c9d0958aa3e377a593ec458f6674ce1ddb2bf3ca158786f09c4"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-sidebar-controls.json",
|
||||
"sha256": "ae9f24746e67432cf6247c5da130b9c1bba46fc85112c0610d3f18545dfce326"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-sidebar.md",
|
||||
"sha256": "5e267441c43aa8375fa5c54edcbd2879428d657708be9a2ab372aa66e4792886"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-timeline-controls.json",
|
||||
"sha256": "6a86b07770f1cd8d758334fb61c46254197a7f533d24c056fc9a52c317488291"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-timeline.md",
|
||||
"sha256": "612dc3ec4c3d435888055ba20a7f28230ce89ea8b071b8c38d1ea2c147074a96"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-transcript-controls.json",
|
||||
"sha256": "9e4dbdc33806d6fcc912dc3aacc8691a77939e2ce2403032b2a8127c0e407e94"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-transcript.md",
|
||||
"sha256": "9e4ac8c92a3a9eca727c29a77ae428702d19ecdee0cab0e3dfcda0a36bf004db"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui.md",
|
||||
"sha256": "896b9928af85a4c7d588dfca93484980aadb238bd79d8142e671c62f0b191fa8"
|
||||
}
|
||||
],
|
||||
"ownerRestoredToBaseGitBytes": true,
|
||||
"productionLinesChanged": 0
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
# Test audit, Round 7 UI — Agent configuration follow-up
|
||||
|
||||
This separate packet removes **4 registered executions, 4 root renders and 44 net test lines** from `ui/src/components/AgentConfigForm.render.test.tsx`. It adds no helper and changes no production lines. Audit base: `e3effbb9e5c66b838f67fd487987c8bf1007e413`. Prior committed evidence remains byte-identical. Render/execution savings are per complete-suite invocation; no measured runtime or CI-speed claim is made.
|
||||
|
||||
## Exact retirement map
|
||||
|
||||
| Retired registration | Keeper | Observations retained |
|
||||
|---|---|---|
|
||||
| `keeps secret access out of the main Configuration content` | `hides the environment override when Local is the only configured environment` | expect(result.container.textContent).not.toContain("Secret access"); |
|
||||
| `starts a login session for the effective sandbox and shows the code and the authentication URL` | `shows a Cancel affordance while a login is active and cancels the session` | expect(mockAgentsApi.startAdapterAuthLogin).toHaveBeenCalledWith("company-1", "codex_local", { environmentId: "sandbox-1", });; expect(result.container.textContent).toContain("WXYZ-1234");; expect(result.container.textContent).toContain("https://auth.example.test/device"); |
|
||||
| `shows the authorization URL and a browser-code input for a Claude sandbox` | `cancels an active Claude login and returns to its start state` | expect(mockAgentsApi.startClaudeSetupTokenLogin).toHaveBeenCalledWith("company-1", { environmentId: "sandbox-1", });; expect(result.container.textContent).toContain("https://claude.example.test/authorize");; expect( result.container.querySelector('input[aria-label="Browser code"]'), ).toBeTruthy();; expect(result.container.textContent).not.toContain("not encrypted"); |
|
||||
| `keeps the non-path ACP controls visible when the policy hides the engine choice` | `hides the host path and execution-engine fields for claude_local when the policy is on` | expect(labels).toContain("ACP session mode");; expect(labels).toContain("ACP non-interactive permissions"); |
|
||||
|
||||
Each of four pairs uses identical beforeEach/afterEach hooks and render/helper input expressions. The Local-only configuration keeper absorbs the Secret access exclusion. The Codex and Claude cancellation keepers retain their respective original provider-specific start API and displayed-code/submitted-browser-code observations before any Cancel click; their providers and lifecycle remain separate. Real runTest/startLogin helpers click Test/Sign in under the original QueryClient/Toast/Tooltip tree with fresh clients and roots. The managed-sandbox-only keeper absorbs both visible non-path ACP labels after the same Advanced/Advanced Run Policy toggles. AgentConfigForm.tsx passes the policy into real ClaudeLocalAdvancedFields from adapters/claude-local/config-fields.tsx, which retains non-path mode/permission fields while host paths are hidden. Existing enabled/disabled/loading, stored-token, terminal-state, submit, cancel-error and timeout cases remain unchanged. Two retired login cases avoid repeated environment-test/start-login API paths; polling request counts and time savings are not claimed.
|
||||
|
||||
The AST verifier checks exact setup, shared enclosing hooks and matched cleanup where present, reconstructs candidate text solely from the declared registrations/assertion migrations, and requires exact byte equality plus full-program AST equality outside those edits. No fixture, helper, provider, action order, wait, assertion strength, timer or teardown changes. The IssueChatThread keeper is an existing complete subset proof; InlineEditor’s identical not-null guard is retained once. Every other case stays byte-identical. Default CI includes this file in `@paperclipai/ui` under `general-workspaces-a`, once across the two file shards; workflow/config unchanged.
|
||||
|
||||
## Complete owner-file results
|
||||
|
||||
| Run | Registered | Passed | Failed | Skipped |
|
||||
|---|---:|---:|---:|---:|
|
||||
| Baseline | 99 | 99 | 0 | 0 |
|
||||
| Candidate | 95 | 95 | 0 | 0 |
|
||||
|
||||
From `ui/`: `pnpm exec vitest run src/components/AgentConfigForm.render.test.tsx`.
|
||||
|
||||
All 13 isolated positive controls passed. All 13 deliberate behavior regressions failed at their intended retained/migrated assertion, rather than setup, timeout or a different guard:
|
||||
|
||||
| Regression | Intended guard |
|
||||
|---|---|
|
||||
| secrets | `expect(result.container.textContent).not.toContain("Secret access")` |
|
||||
| codex-company | `expect(mockAgentsApi.startAdapterAuthLogin).toHaveBeenCalledWith(` |
|
||||
| codex-adapter | `expect(mockAgentsApi.startAdapterAuthLogin).toHaveBeenCalledWith(` |
|
||||
| codex-environment | `expect(mockAgentsApi.startAdapterAuthLogin).toHaveBeenCalledWith(` |
|
||||
| codex-code | `expect(result.container.textContent).toContain("WXYZ-1234")` |
|
||||
| codex-url | `expect(result.container.textContent).toContain("https://auth.example.test/device")` |
|
||||
| claude-company | `expect(mockAgentsApi.startClaudeSetupTokenLogin).toHaveBeenCalledWith(` |
|
||||
| claude-environment | `expect(mockAgentsApi.startClaudeSetupTokenLogin).toHaveBeenCalledWith(` |
|
||||
| claude-url | `expect(result.container.textContent).toContain("https://claude.example.test/authorize")` |
|
||||
| claude-input | `result.container.querySelector('input[aria-label="Browser code"]')` |
|
||||
| claude-advisory | `expect(result.container.textContent).not.toContain("not encrypted")` |
|
||||
| acp-mode | `expect(labels).toContain("ACP session mode")` |
|
||||
| acp-permissions | `expect(labels).toContain("ACP non-interactive permissions")` |
|
||||
|
||||
Exactly one production owner was temporarily changed per control. Every owner was restored byte for byte after each mutation and matched pinned Git bytes. Filtered controls select one keeper; unselected tests do not count as full-suite evidence. [Controls JSON](2026-10-12-test-audit-r7-ui-agentconfig-controls.json) records exact owner/source hashes, migration/input proof, complete-file run/log digests, mutation bodies, intended assertion failures and restoration receipts. Temporary raw verifiers and logs are identified by digests rather than committed in full.
|
||||
|
||||
The earlier broad `pnpm test:run` was intentionally stopped without completion and is not claimed as passed. Separate packet results are focused proof, not a completed combined delivery-head replay or pending full CI. No push, rebase, PR or merge is included here.
|
||||
@@ -0,0 +1,137 @@
|
||||
{
|
||||
"audit": {
|
||||
"file": "ui/src/components/AppErrorBoundary.test.tsx",
|
||||
"base": "c39262305b6b48a5decd564af8369083cd972b33",
|
||||
"originalSha256": "1cc53b4a6978c3c5e98761467208d8e2e9a165163956a64a33bb84cea2778327",
|
||||
"candidateSha256": "51fce35eb3b3b2dd0e1aacdd09f14dcd208e2e6b557ab0e4de9a16606fa3b778",
|
||||
"allOtherProgramAstUnchanged": true,
|
||||
"allOtherSourceBytesUnchanged": true,
|
||||
"newHelpers": 0,
|
||||
"registeredInvocationsRemoved": 1,
|
||||
"rootRendersRemoved": 1,
|
||||
"netTestLinesRemoved": 20,
|
||||
"migrations": [
|
||||
{
|
||||
"retired": "renders a reload prompt instead of a blank page when the shell throws in render",
|
||||
"keeper": "reports one captured error and keeps the reload prompt",
|
||||
"setupAstEqual": true,
|
||||
"setupBindingNormalization": null,
|
||||
"guards": [
|
||||
"expect(container.textContent).toContain(\"Paperclip hit an error\");",
|
||||
"expect(container.textContent).toContain(\"Maximum update depth exceeded\");"
|
||||
],
|
||||
"registeredInvocationsRemoved": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"verifierSha256": "0f1b173c8a399bb8c3e831edac6805634304a749faffcfff7b8b1900da3d34a3",
|
||||
"mutationVerifierSha256": "a05f5ba9071c0ce7ce8eac1bc0f6c7dd83401c4e720816389d779f8919312064",
|
||||
"runs": [
|
||||
{
|
||||
"kind": "baseline",
|
||||
"jsonSha256": "c1a2a5f2da21b5a730f174b628b23c1b01e682b2b8cc10ab8f332dbcede339bd",
|
||||
"logSha256": "475145ce3b58595c9e76cbed628598ecc97a3d5cc835b1e374a10507e72ba9f7",
|
||||
"total": 6,
|
||||
"passed": 6,
|
||||
"failed": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
{
|
||||
"kind": "candidate",
|
||||
"jsonSha256": "b27bec00f8765cc28254633e2752f96f15d6f0734cd59b4e0c10267ba138ff46",
|
||||
"logSha256": "bba83ddd4f7aae20381ef90bfd2f17f6b44818e71994c5f716ea17df8c10c057",
|
||||
"total": 5,
|
||||
"passed": 5,
|
||||
"failed": 0,
|
||||
"skipped": 0
|
||||
}
|
||||
],
|
||||
"mutations": [
|
||||
{
|
||||
"slug": "title",
|
||||
"owner": "ui/src/components/AppErrorBoundary.tsx",
|
||||
"sourceSha256": "72bfc237fd0760e8432a9948e3423b6cab6881507f28815240f585f46e3ceb7c",
|
||||
"title": "reports one captured error and keeps the reload prompt",
|
||||
"mutation": {
|
||||
"before": "Paperclip hit an error",
|
||||
"after": "Unexpected title",
|
||||
"replacementCount": 1,
|
||||
"additionalPreClosingTagReplacement": false
|
||||
},
|
||||
"intendedGuard": "expect(container.textContent).toContain(\"Paperclip hit an error\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "85d36ca8369f85ceb5e9173db5670b2d5ccf3c843cf26b3b1fb0ddb73a59a029",
|
||||
"logSha256": "088a6c3c7dafb9546d8c32db0829797a2917cba4ce2e78c0215529c99d9096f2",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "b82c5bc57625cae251acafe46aa64021129848550e43cb66c19996b10f7ced0f",
|
||||
"logSha256": "5f8f8ad95575b5920ae4574c4c04d7d7a6b3db3262c293973953b4f56f2f6604",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected 'Unexpected titleSomething went wrong \u2026' to contain 'Paperclip hit an error'\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/AppErrorBoundary.test.tsx:53:35\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:1628:35\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:26\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3321:20\n at new Promise (<anonymous>)\n at runWithCancel (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3316:10)\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3301:20\n at new Promise (<anonymous>)\n at runWithTimeout (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3259:10)\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3882:64"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "detail",
|
||||
"owner": "ui/src/components/AppErrorBoundary.tsx",
|
||||
"sourceSha256": "72bfc237fd0760e8432a9948e3423b6cab6881507f28815240f585f46e3ceb7c",
|
||||
"title": "reports one captured error and keeps the reload prompt",
|
||||
"mutation": {
|
||||
"before": "{error.message}",
|
||||
"after": "{\"hidden detail\"}",
|
||||
"replacementCount": 1,
|
||||
"additionalPreClosingTagReplacement": false
|
||||
},
|
||||
"intendedGuard": "expect(container.textContent).toContain(\"Maximum update depth exceeded\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "a11dcafca2602e4baed9feff4925dcca4c09ceb46a36b5baf782742274fe467d",
|
||||
"logSha256": "23301c06f7a3c46599867040f2fe947f36fe6bf9c33c66e6c0d465c9b7a97746",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "3d0fdd9f0f6fa788decca2bdf816bee3bcbe4f2d5836ba6582e8e2860369d974",
|
||||
"logSha256": "31c8775a1049760ef218a4d1bb14df2dde621652cd58f1b53c24651a4dfa0d3a",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected 'Paperclip hit an errorSomething went \u2026' to contain 'Maximum update depth exceeded'\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/AppErrorBoundary.test.tsx:54:35\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:1628:35\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:26\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3321:20\n at new Promise (<anonymous>)\n at runWithCancel (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3316:10)\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3301:20\n at new Promise (<anonymous>)\n at runWithTimeout (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3259:10)\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3882:64"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"priorEvidenceUnchanged": [
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appdetail-controls.json",
|
||||
"sha256": "7906fde0d62e14a7511b5cf45f864c9386a4c377922333eefc7f7e703c832f6a"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appdetail.md",
|
||||
"sha256": "715f23cd27502c92d0f5d1b83b91bcac03f254c73ab63b44181ae76939805229"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-controls.json",
|
||||
"sha256": "0d445f6f066032f2d9cd724525a8d7d2290246cbfeee1f6ab4b44818467af2a7"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-transcript-controls.json",
|
||||
"sha256": "9e4dbdc33806d6fcc912dc3aacc8691a77939e2ce2403032b2a8127c0e407e94"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-transcript.md",
|
||||
"sha256": "9e4ac8c92a3a9eca727c29a77ae428702d19ecdee0cab0e3dfcda0a36bf004db"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui.md",
|
||||
"sha256": "896b9928af85a4c7d588dfca93484980aadb238bd79d8142e671c62f0b191fa8"
|
||||
}
|
||||
],
|
||||
"ownerRestoredToBaseGitBytes": true,
|
||||
"productionLinesChanged": 0
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
# Test audit, Round 7 UI — App error boundary follow-up
|
||||
|
||||
This isolated follow-up removes **1 registered executions, 1 root renders and 20 net test lines** from `ui/src/components/AppErrorBoundary.test.tsx`. It changes no production lines and adds no helper. The pinned audit base is `c39262305b6b48a5decd564af8369083cd972b33`. Prior UI proof remains unchanged. Registration/render reductions are per complete-suite invocation; no measured runtime or CI-speed claim is made.
|
||||
|
||||
## Exact migrations
|
||||
|
||||
| Retired registration | Keeper | Original observations retained |
|
||||
|---|---|---|
|
||||
| `renders a reload prompt instead of a blank page when the shell throws in render` | `reports one captured error and keeps the reload prompt` | expect(container.textContent).toContain("Paperclip hit an error");; expect(container.textContent).toContain("Maximum update depth exceeded"); |
|
||||
|
||||
main.tsx wraps the app in AppErrorBoundary. The paired tests create the same root and render the same BoomRender throw under the real boundary, with identical hooks/unmount. Move title and original error detail before retained capture/count/metadata/reload-button checks. The retired reload-button expression already matches the retained expression exactly. Effect errors, healthy children and DOM insertion/translation errors remain distinct and unchanged.
|
||||
|
||||
The verifier reconstructs the exact candidate text from only the declared removals and insertions, requires byte equality, and compares the entire program AST after the same migrations. Every unrelated source byte, hook, mock, test body and binding remains unchanged, outside the audit receipt’s explicitly declared duplicate-title or blank-line cleanup where applicable. Setup ASTs are equal except the explicitly normalized attachment callback binding described above where applicable. No tests are skipped, softened, suppressed or added. Each file remains included in `@paperclipai/ui` under CI `general-workspaces-a`; Vitest file sharding selects it once across the two shards, with no workflow/config change.
|
||||
|
||||
## Complete-file evidence
|
||||
|
||||
| Run | Registered | Passed | Failed | Skipped |
|
||||
|---|---:|---:|---:|---:|
|
||||
| Baseline | 6 | 6 | 0 | 0 |
|
||||
| Candidate | 5 | 5 | 0 | 0 |
|
||||
|
||||
From `ui/`: `pnpm exec vitest run src/components/AppErrorBoundary.test.tsx`.
|
||||
|
||||
All 2 separately selected positive keeper controls passed. Every deliberate behavior mutation failed at the corresponding intended keeper assertion, not setup, timeout or another guard:
|
||||
|
||||
| Mutation | Intended assertion |
|
||||
|---|---|
|
||||
| title | `expect(container.textContent).toContain("Paperclip hit an error")` |
|
||||
| detail | `expect(container.textContent).toContain("Maximum update depth exceeded")` |
|
||||
|
||||
Every mutated production owner was restored byte for byte after each mutation and checked against pinned Git bytes. Name-filtered controls select exactly one keeper; their unselected tests are not full-suite evidence. [Compact controls](2026-10-12-test-audit-r7-ui-appboundary-controls.json) preserve source/owner hashes, exact migration map, body verifier digests, complete run/log digests, intended failure receipts and restoration checks. Temporary AST/receipt scripts initially needed corrections for chained assertions or statement position; those verifier attempts produced no accepted test evidence.
|
||||
|
||||
The earlier broad local `pnpm test:run` was intentionally stopped before completion; it is not claimed as a pass. These focused runs do not substitute for pending delivery-head CI. No push, rebase, pull request or merge is included in this packet.
|
||||
@@ -0,0 +1,103 @@
|
||||
{
|
||||
"audit": {
|
||||
"file": "ui/src/pages/apps/AppDetail.test.tsx",
|
||||
"base": "81cd7ab0ca0bdc55ea0927bc44fcf6e764a530ed",
|
||||
"originalSha256": "35c4d4828daa80d37b8319fa1dfd4c049c03e26a780c6ce3b1e64990f32be9c6",
|
||||
"candidateSha256": "f41c56cc4bae6e496067c93b58419ed3acfc6938f7a1ea7169ac2b1fa9ae3e61",
|
||||
"retired": "removes the separate always-installed controls from Permissions",
|
||||
"keeper": "renders searchable action groups with three-way permission toggles",
|
||||
"identicalInitialSetup": true,
|
||||
"migratedExactAssertions": [
|
||||
"expect(container.textContent).toContain(\"Which agents can use this connection?\");",
|
||||
"expect(container.textContent).not.toContain(\"Always installed\");",
|
||||
"expect(putConnectionInstallsMock).not.toHaveBeenCalled();"
|
||||
],
|
||||
"allOtherSourceBytesUnchanged": true,
|
||||
"allOtherProgramAstUnchanged": true,
|
||||
"newHelpers": 0,
|
||||
"registeredInvocationsRemoved": 1,
|
||||
"completeRenderCallsRemoved": 1,
|
||||
"netTestLinesRemoved": 7
|
||||
},
|
||||
"verifierSha256": "8252a8caeedbbbc3b6b630376b8207b4f78021b719ac601e061d394535ecea0e",
|
||||
"runs": [
|
||||
{
|
||||
"kind": "baseline",
|
||||
"jsonSha256": "74eb47f37400e2409108c4a88bbbd1f0c25d12d0e7f9c8576aad598758472ea3",
|
||||
"total": 78,
|
||||
"passed": 78,
|
||||
"failed": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
{
|
||||
"kind": "candidate",
|
||||
"jsonSha256": "50a8a2e03f8521f125011f82c0ee816b55e1bd1d751e9d3fd2fe3fd71fad2314",
|
||||
"total": 77,
|
||||
"passed": 77,
|
||||
"failed": 0,
|
||||
"skipped": 0
|
||||
}
|
||||
],
|
||||
"mutations": [
|
||||
{
|
||||
"slug": "appdetail-old-install-copy",
|
||||
"owner": "ui/src/pages/apps/app-detail/PermissionsPanel.tsx",
|
||||
"title": "renders searchable action groups with three-way permission toggles",
|
||||
"sourceSha": "b3b96c2e2fbafee17e0b01c9127c30bd4a0a787f2481a264001fd6c2bce8e379",
|
||||
"replacements": 1,
|
||||
"mutation": {
|
||||
"before": ">Which agents can use this connection?</h2>",
|
||||
"after": ">Which agents can use this connection?<span>Always installed</span></h2>"
|
||||
},
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"caseStatus": "passed",
|
||||
"jsonSha256": "a97f5dd88c5febcf4fe906f34ea7efd0672781b95b2757aeb9cbcb0bd9247edf",
|
||||
"logSha256": "26c7c2d6e1c6edca6e56e0f21ecbe3897c28c3f7ad1300dd07886fe905d0c025"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"caseStatus": "failed",
|
||||
"intendedAssertionFailure": "AssertionError: expected 'GitHubConnected2 actions availableUnv\u2026' not to contain 'Always installed'",
|
||||
"jsonSha256": "a444c1fbc181dabecbcf67ce1ea7da5659d2bf3cc85a5983fc02fd49418ea66d",
|
||||
"logSha256": "feef1c4c056f2bba80e2bda438edc27e099da834f11d3c5b1ccaf1e13da73b0d"
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "appdetail-install-on-mount",
|
||||
"owner": "ui/src/pages/apps/AppDetail.tsx",
|
||||
"title": "renders searchable action groups with three-way permission toggles",
|
||||
"sourceSha": "ee8ab6e844ce11bf5d13954f0a73de3e42de61a933deb01ad9e40cb76e3b93d1",
|
||||
"replacements": 1,
|
||||
"mutation": {
|
||||
"before": " const activeTab: AppTabKey | null = isAppTabKey(tab) ? tab : null;",
|
||||
"after": " useEffect(() => { void toolsApi.putConnectionInstalls(connectionId, []); }, [connectionId]);\n const activeTab: AppTabKey | null = isAppTabKey(tab) ? tab : null;"
|
||||
},
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"caseStatus": "passed",
|
||||
"jsonSha256": "b87e88f3d6a624d21ce9795889d002fb0bb8a08ad7b27bd5cad6420b03ec6f04",
|
||||
"logSha256": "0d0d9d88fd6da2c652fb4119fb2ed3cef7c624514e8b0501f3daf62578ec99ac"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"caseStatus": "failed",
|
||||
"intendedAssertionFailure": "AssertionError: expected \"vi.fn()\" to not be called at all, but actually been called 1 times",
|
||||
"jsonSha256": "7d04f5db02f84793fe53914e4f8cfc98f7644766146861857afcf586809b6d16",
|
||||
"logSha256": "cc98a64e983162d6330263ea4433cc6b17c4925b3b9806794996dafb9b7acd0c"
|
||||
}
|
||||
}
|
||||
],
|
||||
"allProductionOwnersRestored": true,
|
||||
"productionLinesChanged": 0,
|
||||
"priorUiProofUnchanged": {
|
||||
"commit": "81cd7ab0ca0bdc55ea0927bc44fcf6e764a530ed",
|
||||
"reportSha256": "896b9928af85a4c7d588dfca93484980aadb238bd79d8142e671c62f0b191fa8",
|
||||
"controlsSha256": "0d445f6f066032f2d9cd724525a8d7d2290246cbfeee1f6ab4b44818467af2a7"
|
||||
},
|
||||
"ciInclusion": "@paperclipai/ui project in general-workspaces-a; complete file remains included; no routing changes",
|
||||
"netCombinedTestLinesRemoved": 371,
|
||||
"combinedRegisteredInvocationsRemoved": 2
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
# Test audit, Round 7 UI — AppDetail follow-up
|
||||
|
||||
This follow-up removes **one duplicate registered invocation, one complete render, and seven net test lines** from `ui/src/pages/apps/AppDetail.test.tsx`. It adds no helper and changes zero production lines. Combined with the [approved first UI batch](2026-10-12-test-audit-r7-ui.md), the branch removes **371 net test lines and two registered invocations**. The original UI report, controls and test bytes remain unchanged.
|
||||
|
||||
The follow-up audit base is local UI commit `81cd7ab0ca0bdc55ea0927bc44fcf6e764a530ed`. This file has the same original bytes at Round 6 parent `e868e6645ce0d598d756d3458f0b3d71afd6db4a`.
|
||||
|
||||
## Exact retirement and keeper
|
||||
|
||||
Retired: `removes the separate always-installed controls from Permissions`.
|
||||
|
||||
Keeper: `renders searchable action groups with three-way permission toggles`.
|
||||
|
||||
Both cases use the same enclosing beforeEach, connection, catalog, profiles, grants, install state and spies. Their two pre-assertion statements are byte-identical: select the permissions tab, then await the same complete AppDetail render. Neither case changes a fixture or takes a user action before its assertions. Both permission observations were updated by [PR #12802](https://github.com/paperclipai/paperclip/pull/12802).
|
||||
|
||||
All three retired observations move unchanged into the keeper, immediately after render and before its existing assertions:
|
||||
|
||||
- The agent-access question is visible.
|
||||
- The old Always installed copy is absent.
|
||||
- The connection-install mutation API has not been called.
|
||||
|
||||
The keeper also retains its original fixed action-group counts, action names, review prompt, search input, selected Allowed/Ask first radio states, two Test actions, old-copy exclusions and card-layout exclusion. Viewer gates, picked-agent mode, required installed agents, access mutations, AI credential routing, task-grant removal and failure paths remain separate cases.
|
||||
|
||||
App.tsx mounts AppDetail at `apps/:connectionId/:tab`. AppDetail's actual permissions path renders AgentAccessSection and ActionsSection in PermissionsPanel. AgentAccessSection supplies the question and access controls. The install API is used by the explicit AI-connection save path, so a no-write-on-read check is a separate observation from absent UI copy. Both fixed guards remain in the keeper. The grouped action-control sibling suite remains unchanged.
|
||||
|
||||
The test stays in the `@paperclipai/ui` project and the `general-workspaces-a` lane. This cut removes a collected test and its full query-client/root render; it changes no suite inclusion or CI routing. No wall-time improvement is claimed.
|
||||
|
||||
## Proof
|
||||
|
||||
| Complete AppDetail file | Registered cases | Passed | Failed | Skipped |
|
||||
|---|---:|---:|---:|---:|
|
||||
| Baseline | 78 | 78 | 0 | 0 |
|
||||
| Candidate | 77 | 77 | 0 | 0 |
|
||||
|
||||
Run from `ui/`: `pnpm exec vitest run src/pages/apps/AppDetail.test.tsx`.
|
||||
|
||||
The body audit checks the two identical setup statements, copies the three exact assertion ASTs, and compares full original/candidate programs outside the declared removal and insertion. It also reconstructs the exact candidate text from only those source edits and requires byte equality. Every other source byte remains unchanged, including all mock factories, beforeEach, render helper, spies, waits, cleanup and original keeper assertions. No withPermissions helper exists in these pinned file bytes; no such setup was added or changed.
|
||||
|
||||
Both positive keeper controls passed. Two deliberately broken production owners failed at the intended migrated guard:
|
||||
|
||||
| Production regression | Direct keeper failure |
|
||||
|---|---|
|
||||
| Reintroduce Always installed copy beside the access question in PermissionsPanel | Fixed negative old-copy assertion. |
|
||||
| Write connection installs from an AppDetail mount effect | Fixed no-install-API-call assertion. |
|
||||
|
||||
Each negative control selected only the keeper. Its unselected cases do not count as complete-file proof. Neither mutation failed on setup, timeout or an unrelated action assertion. Both production owners were restored byte for byte and checked against pinned Git source.
|
||||
|
||||
[Follow-up controls](2026-10-12-test-audit-r7-ui-appdetail-controls.json) retain exact original/candidate hashes, the unchanged prior proof hashes, body-audit digest, complete-file results, mutation descriptions, intended failures, run/log digests and source-restoration receipts. Raw verifiers and logs remain temporary audit packets; their digests do not retain complete payloads. Latest delivery-head replay, typecheck, token gates, build and CI status belong in the PR. The broad local default run was stopped before completion as recorded by the coordinator; it is not a full-suite pass.
|
||||
@@ -0,0 +1,168 @@
|
||||
{
|
||||
"audit": {
|
||||
"file": "ui/src/components/IssueAttachmentsSection.test.tsx",
|
||||
"base": "c39262305b6b48a5decd564af8369083cd972b33",
|
||||
"originalSha256": "938aead11f9ccd2246049fe7ebe82800c3bdc8ff7c17fc20017d03ecc659d73a",
|
||||
"candidateSha256": "e7cc76d20708169e8eadba692d6f9bc9e7ba32cb18075e72c8aaceb420705a94",
|
||||
"allOtherProgramAstUnchanged": true,
|
||||
"allOtherSourceBytesUnchanged": true,
|
||||
"newHelpers": 0,
|
||||
"registeredInvocationsRemoved": 1,
|
||||
"rootRendersRemoved": 1,
|
||||
"netTestLinesRemoved": 22,
|
||||
"migrations": [
|
||||
{
|
||||
"retired": "renders video attachments through the same player used for artifact outputs",
|
||||
"keeper": "lets video attachments open the shared media gallery",
|
||||
"setupAstEqual": false,
|
||||
"setupBindingNormalization": "Inline fresh vi.fn becomes existing keeper fresh named vi.fn; provider/attachment/delete callback/flush unchanged",
|
||||
"guards": [
|
||||
"const video = container.querySelector(\"video\");",
|
||||
"expect(video?.getAttribute(\"src\")).toBe(\"/api/attachments/video-attachment/content\");",
|
||||
"expect(video?.getAttribute(\"controls\")).not.toBeNull();",
|
||||
"expect(fetchSpy).not.toHaveBeenCalled();"
|
||||
],
|
||||
"registeredInvocationsRemoved": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"verifierSha256": "0f1b173c8a399bb8c3e831edac6805634304a749faffcfff7b8b1900da3d34a3",
|
||||
"mutationVerifierSha256": "a05f5ba9071c0ce7ce8eac1bc0f6c7dd83401c4e720816389d779f8919312064",
|
||||
"runs": [
|
||||
{
|
||||
"kind": "baseline",
|
||||
"jsonSha256": "41996a845a818368c4fe0a7a4b31474ddc1b35c56c9aff524dcfae3218a1112c",
|
||||
"logSha256": "cf1b9e033afd854462df31d4d65f4e604f317f6473c1f75c25b91ccf46e3e92c",
|
||||
"total": 8,
|
||||
"passed": 8,
|
||||
"failed": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
{
|
||||
"kind": "candidate",
|
||||
"jsonSha256": "e9db5edd68d2e89898848aa90dabf75957fb703813c429472f80fbae92d194b4",
|
||||
"logSha256": "67fe4596626962ac86f547b251f992158d5a28063a2c62962816433c3e837ed2",
|
||||
"total": 7,
|
||||
"passed": 7,
|
||||
"failed": 0,
|
||||
"skipped": 0
|
||||
}
|
||||
],
|
||||
"mutations": [
|
||||
{
|
||||
"slug": "source",
|
||||
"owner": "ui/src/components/IssueAttachmentsSection.tsx",
|
||||
"sourceSha256": "2ba7827325ed63d57fad24f31144e54c48c0618584c0cd013b26acf93e7f525b",
|
||||
"title": "lets video attachments open the shared media gallery",
|
||||
"mutation": {
|
||||
"before": "<OutputVideoPlayer src={attachment.contentPath} title={filename} />",
|
||||
"after": "<OutputVideoPlayer src=\"/wrong-video.webm\" title={filename} />",
|
||||
"replacementCount": 1,
|
||||
"additionalPreClosingTagReplacement": false
|
||||
},
|
||||
"intendedGuard": "expect(video?.getAttribute(\"src\")).toBe(",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "26bb673ede3119522a715a31928f8066c41c6538e78139e5a1dde1e879964fd5",
|
||||
"logSha256": "5f31a93058981f8a4a0b9c109b851aad78153f734eb723cc04998fb3ffca555b",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "41c490f0613aaf4958ad6ccc613dcf31053f2f528b1c7b2a252230470bc7d8ae",
|
||||
"logSha256": "984bfe91fe92dcb4518504ae6fe21205466e3c775c2dde6806934471d73ab7d5",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected '/wrong-video.webm' to be '/api/attachments/video-attachment/con\u2026' // Object.is equality\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/IssueAttachmentsSection.test.tsx:206:40\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "controls",
|
||||
"owner": "ui/src/components/IssueAttachmentsSection.tsx",
|
||||
"sourceSha256": "2ba7827325ed63d57fad24f31144e54c48c0618584c0cd013b26acf93e7f525b",
|
||||
"title": "lets video attachments open the shared media gallery",
|
||||
"mutation": {
|
||||
"before": "<OutputVideoPlayer src={attachment.contentPath} title={filename} />",
|
||||
"after": "<video src={attachment.contentPath} />",
|
||||
"replacementCount": 1,
|
||||
"additionalPreClosingTagReplacement": false
|
||||
},
|
||||
"intendedGuard": "expect(video?.getAttribute(\"controls\")).not.toBeNull()",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "5f63925596e95dc930e831668536812e50bb21f3c49e5d6d72458b4fe8e9558d",
|
||||
"logSha256": "9685b1259ff56dade8aee65c3388084bb032c0a1bd584e7635cf64a90ae7ef34",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "738045b821839a3fe5b3ff8ab0c8abd6508462105a7ffde2ae24cd2a76d0f1e5",
|
||||
"logSha256": "19e35c954f8972b9d86f893ee59877ad1ee28eaff8856c22fdeac4f4f49ebfab",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected null not to be null\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/IssueAttachmentsSection.test.tsx:207:49\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "fetch",
|
||||
"owner": "ui/src/components/IssueAttachmentsSection.tsx",
|
||||
"sourceSha256": "2ba7827325ed63d57fad24f31144e54c48c0618584c0cd013b26acf93e7f525b",
|
||||
"title": "lets video attachments open the shared media gallery",
|
||||
"mutation": {
|
||||
"before": " const filename = attachmentFilename(attachment);\n return (\n <Card id={`attachment-${attachment.id}`} className=\"block scroll-mt-20 overflow-hidden py-0\">",
|
||||
"after": " const filename = attachmentFilename(attachment);\n void fetch(attachment.contentPath);\n return (\n <Card id={`attachment-${attachment.id}`} className=\"block scroll-mt-20 overflow-hidden py-0\">",
|
||||
"replacementCount": 1,
|
||||
"additionalPreClosingTagReplacement": false
|
||||
},
|
||||
"intendedGuard": "expect(fetchSpy).not.toHaveBeenCalled()",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "fa3a3edf2518552cf54db294e33be650bbf026a1b9505f8dfd4b7baba5de5d8d",
|
||||
"logSha256": "1ba024b01f756729fdfbc1a7f9b535b8cd16a650bc1da99d8ea9d5a79521f796",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "b43dea15a78ffa00aa10d67a79932d6b8bba5a6a57d8dfb828d8693e277e019b",
|
||||
"logSha256": "130e9a50e1cb3db653a4324ce9aa86b785d9275436606793f823073f6432ab0d",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected \"vi.fn()\" to not be called at all, but actually been called 1 times\n\nReceived:\n\n 1st vi.fn() call:\n\n Array [\n \"/api/attachments/video-attachment/content\",\n ]\n\n\nNumber of calls: 1\n\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:2214:51)\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:1944:14)\n at Proxy.methodWrapper (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/chai@6.3.0/node_modules/chai/index.js:1737:25)\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/IssueAttachmentsSection.test.tsx:208:26\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"priorEvidenceUnchanged": [
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appdetail-controls.json",
|
||||
"sha256": "7906fde0d62e14a7511b5cf45f864c9386a4c377922333eefc7f7e703c832f6a"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appdetail.md",
|
||||
"sha256": "715f23cd27502c92d0f5d1b83b91bcac03f254c73ab63b44181ae76939805229"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-controls.json",
|
||||
"sha256": "0d445f6f066032f2d9cd724525a8d7d2290246cbfeee1f6ab4b44818467af2a7"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-transcript-controls.json",
|
||||
"sha256": "9e4dbdc33806d6fcc912dc3aacc8691a77939e2ce2403032b2a8127c0e407e94"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-transcript.md",
|
||||
"sha256": "9e4ac8c92a3a9eca727c29a77ae428702d19ecdee0cab0e3dfcda0a36bf004db"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui.md",
|
||||
"sha256": "896b9928af85a4c7d588dfca93484980aadb238bd79d8142e671c62f0b191fa8"
|
||||
}
|
||||
],
|
||||
"ownerRestoredToBaseGitBytes": true,
|
||||
"productionLinesChanged": 0
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
# Test audit, Round 7 UI — Video attachments follow-up
|
||||
|
||||
This isolated follow-up removes **1 registered executions, 1 root renders and 22 net test lines** from `ui/src/components/IssueAttachmentsSection.test.tsx`. It changes no production lines and adds no helper. The pinned audit base is `c39262305b6b48a5decd564af8369083cd972b33`. Prior UI proof remains unchanged. Registration/render reductions are per complete-suite invocation; no measured runtime or CI-speed claim is made.
|
||||
|
||||
## Exact migrations
|
||||
|
||||
| Retired registration | Keeper | Original observations retained |
|
||||
|---|---|---|
|
||||
| `renders video attachments through the same player used for artifact outputs` | `lets video attachments open the shared media gallery` | const video = container.querySelector("video");; expect(video?.getAttribute("src")).toBe("/api/attachments/video-attachment/content");; expect(video?.getAttribute("controls")).not.toBeNull();; expect(fetchSpy).not.toHaveBeenCalled(); |
|
||||
|
||||
IssueAttachmentsSection.tsx classifies the same webm attachment into VideoAttachmentCard, which passes contentPath to the actual shared OutputVideoPlayer; OutputVideoPlayer supplies native controls. Gallery forwarding stays in AttachmentActions. Both tests use the same makeAttachment overrides, fresh query client/root/fetchSpy hooks, delete callback presence and act/flush lifecycle. The retired inline fresh vi.fn for onImageClick matches the existing keeper fresh named vi.fn after binding normalization; the keeper binding remains unchanged. Move video source, controls and no-fetch checks before gallery click. MIME fallback, non-video/non-markdown, generic download and read-only tests remain distinct.
|
||||
|
||||
The verifier reconstructs the exact candidate text from only the declared removals and insertions, requires byte equality, and compares the entire program AST after the same migrations. Every unrelated source byte, hook, mock, test body and binding remains unchanged, outside the audit receipt’s explicitly declared duplicate-title or blank-line cleanup where applicable. Setup ASTs are equal except the explicitly normalized attachment callback binding described above where applicable. No tests are skipped, softened, suppressed or added. Each file remains included in `@paperclipai/ui` under CI `general-workspaces-a`; Vitest file sharding selects it once across the two shards, with no workflow/config change.
|
||||
|
||||
## Complete-file evidence
|
||||
|
||||
| Run | Registered | Passed | Failed | Skipped |
|
||||
|---|---:|---:|---:|---:|
|
||||
| Baseline | 8 | 8 | 0 | 0 |
|
||||
| Candidate | 7 | 7 | 0 | 0 |
|
||||
|
||||
From `ui/`: `pnpm exec vitest run src/components/IssueAttachmentsSection.test.tsx`.
|
||||
|
||||
All 3 separately selected positive keeper controls passed. Every deliberate behavior mutation failed at the corresponding intended keeper assertion, not setup, timeout or another guard:
|
||||
|
||||
| Mutation | Intended assertion |
|
||||
|---|---|
|
||||
| source | `expect(video?.getAttribute("src")).toBe(` |
|
||||
| controls | `expect(video?.getAttribute("controls")).not.toBeNull()` |
|
||||
| fetch | `expect(fetchSpy).not.toHaveBeenCalled()` |
|
||||
|
||||
Every mutated production owner was restored byte for byte after each mutation and checked against pinned Git bytes. Name-filtered controls select exactly one keeper; their unselected tests are not full-suite evidence. [Compact controls](2026-10-12-test-audit-r7-ui-attachments-controls.json) preserve source/owner hashes, exact migration map, body verifier digests, complete run/log digests, intended failure receipts and restoration checks. Temporary AST/receipt scripts initially needed corrections for chained assertions or statement position; those verifier attempts produced no accepted test evidence.
|
||||
|
||||
The earlier broad local `pnpm test:run` was intentionally stopped before completion; it is not claimed as a pass. These focused runs do not substitute for pending delivery-head CI. No push, rebase, pull request or merge is included in this packet.
|
||||
@@ -0,0 +1,401 @@
|
||||
{
|
||||
"audit": {
|
||||
"file": "ui/src/components/SidebarCompanyMenu.test.tsx",
|
||||
"base": "2e76f5157240ee8b2d42adbdcd4c345aea07c013",
|
||||
"originalSha256": "ad89f1174a840f7e10a04c180dcdfcbb972e66e96fd45a335d4af90da553f693",
|
||||
"candidateSha256": "3b14e39deb667f2b9f79981767b6f47852ed4a8f3ee51fe39c4bd9efbd61d5d2",
|
||||
"allOtherProgramAstUnchanged": true,
|
||||
"allOtherSourceBytesUnchanged": true,
|
||||
"newHelpers": 0,
|
||||
"registeredInvocationsRemoved": 1,
|
||||
"renderInvocationsRemoved": 1,
|
||||
"setupInvocationsRemoved": 1,
|
||||
"netTestLinesRemoved": 28,
|
||||
"migrations": [
|
||||
{
|
||||
"retired": "uses company-centric create copy without the chat flag",
|
||||
"keeper": "toggles company order editing without selecting a company",
|
||||
"exactLeadingStatements": 7,
|
||||
"sameEnclosingHooks": true,
|
||||
"explicitCleanupAstEqual": true,
|
||||
"kind": "menu",
|
||||
"exactMigratedStatements": [
|
||||
"expect(trigger?.classList).toContain(\"px-4\");",
|
||||
"expect(trigger?.classList).toContain(\"has-[>svg]:px-4\");",
|
||||
"expect(trigger?.classList).toContain(\"hover:bg-sidebar-accent\");",
|
||||
"expect(trigger?.classList).toContain(\"hover:text-sidebar-accent-foreground\");",
|
||||
"expect(trigger?.classList).toContain(\"dark:hover:bg-sidebar-accent\");",
|
||||
"expect(trigger?.classList).toContain(\"dark:hover:text-sidebar-accent-foreground\");",
|
||||
"expect(trigger?.classList).not.toContain(\"hover:bg-background\");",
|
||||
"expect(trigger?.classList).not.toContain(\"dark:hover:bg-background\");",
|
||||
"expect(trigger?.classList).not.toContain(\"dark:hover:bg-accent/50\");",
|
||||
"expect(document.body.textContent).toContain(\"Create organization\");",
|
||||
"expect(document.body.textContent).not.toContain(\"Add company...\");"
|
||||
],
|
||||
"alreadyExactKeeperStatementsOrBindings": [
|
||||
"act(() => {\n trigger?.dispatchEvent(new PointerEvent(\"pointerdown\", { bubbles: true, button: 0 }));\n trigger?.dispatchEvent(new MouseEvent(\"click\", { bubbles: true }));\n });",
|
||||
"await flushReact();"
|
||||
],
|
||||
"registeredInvocationsRemoved": 1,
|
||||
"renderInvocationsRemoved": 1,
|
||||
"setupInvocationsRemoved": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"verifierSha256": "ff07f5e2e308cfc0f26584a6cd6599bcd98665e79d7f4782ed5bb36b35cb8cb9",
|
||||
"mutationVerifierSha256": "676b973d4838ed130c5ae92d4bc50fb32a65309af8c858450ec34bcce13729e9",
|
||||
"runs": [
|
||||
{
|
||||
"kind": "baseline",
|
||||
"total": 16,
|
||||
"passed": 16,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"jsonSha256": "b7e2061f311e86d6750c2c9b0e6aee6bd6e026ee7acd10483c3d0cb8de863ac8",
|
||||
"logSha256": "bce8c6310d9cbd08d01f813b90d9115241d8809314b74211530ef05f6c3cfd27"
|
||||
},
|
||||
{
|
||||
"kind": "candidate",
|
||||
"total": 15,
|
||||
"passed": 15,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"jsonSha256": "122222983e6eb17dfcc0745805ae2662a4ebf0781b4811cff488cfaa65f5dd79",
|
||||
"logSha256": "46a93fb15df0d8faae9d94c9c261e1901ec12456bc0eb7610aa0c80cc4c1b58b"
|
||||
}
|
||||
],
|
||||
"mutations": [
|
||||
{
|
||||
"slug": "trigger-inset",
|
||||
"owner": "ui/src/components/SidebarCompanyMenu.tsx",
|
||||
"sourceSha256": "2ea2c865a3e9817c140d3bf269a0c4f45d85a957f11b64d1a84e88926fe1b97a",
|
||||
"title": "toggles company order editing without selecting a company",
|
||||
"mutation": {
|
||||
"before": "gap-2 px-4 text-left",
|
||||
"after": "gap-2 px-2 text-left",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(trigger?.classList).toContain(\"px-4\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "965e51bf2e7303dc08ed66d5758ef80bfb18f8852e967fb12dd9c05776422dd6",
|
||||
"logSha256": "3d45f3d012ad3ffbe563e1150356387730e5e6d2c169a25b537bb7add31124fb",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "f20cf3f9ecda2e5fe608bcd28d9bd68e030c6b72b3bc1bc4edce7e895cfe3ba6",
|
||||
"logSha256": "80548eebd34f5ed3546ce6dc68d47a8e6452ecae6a06a36b6e4e3dc34598cdda",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected \"inline-flex items-center whitespace-nowrap rounded-md text-sm font-medium transition-(--tp-color-background-color-border-color-box-shadow-opacity) disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-(length:--rad-3) aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive py-2 h-9 min-w-0 flex-1 justify-start gap-2 px-2 text-left hover:bg-sidebar-accent hover:text-sidebar-accent-foreground has-[>svg]:px-4 dark:hover:bg-sidebar-accent dark:hover:text-sidebar-accent-foreground\" to contain \"px-4\"\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/SidebarCompanyMenu.test.tsx:429:32\n at runNextTicks (node:internal/process/task_queues:65:5)\n at listOnTimeout (node:internal/timers:567:9)\n at processTimers (node:internal/timers:541:7)\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "icon-inset",
|
||||
"owner": "ui/src/components/SidebarCompanyMenu.tsx",
|
||||
"sourceSha256": "2ea2c865a3e9817c140d3bf269a0c4f45d85a957f11b64d1a84e88926fe1b97a",
|
||||
"title": "toggles company order editing without selecting a company",
|
||||
"mutation": {
|
||||
"before": "has-[>svg]:px-4",
|
||||
"after": "has-[>svg]:px-2",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(trigger?.classList).toContain(\"has-[>svg]:px-4\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "ea88a40c8b8bf6350d02344b57ed5d99783dc5f153b7abb4b3a344c994b7a0f3",
|
||||
"logSha256": "6edb24fc26547ae0367a8d95a2e35530798bb07ce5f71d9f41b86001c4ee6c64",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "fc33c2e6d3e034a617bf247b3795f136b4e5d200b3a4323101df92ce7cc1d7ab",
|
||||
"logSha256": "77d5d26f406f4c778dcd6a6c476577151cefd36b3e0e9b896bd21bfc4d435886",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected \"inline-flex items-center whitespace-nowrap rounded-md text-sm font-medium transition-(--tp-color-background-color-border-color-box-shadow-opacity) disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-(length:--rad-3) aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive py-2 h-9 min-w-0 flex-1 justify-start gap-2 px-4 text-left hover:bg-sidebar-accent hover:text-sidebar-accent-foreground has-[>svg]:px-2 dark:hover:bg-sidebar-accent dark:hover:text-sidebar-accent-foreground\" to contain \"has-[>svg]:px-4\"\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/SidebarCompanyMenu.test.tsx:430:32\n at runNextTicks (node:internal/process/task_queues:65:5)\n at listOnTimeout (node:internal/timers:567:9)\n at processTimers (node:internal/timers:541:7)\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "hover-background",
|
||||
"owner": "ui/src/components/SidebarCompanyMenu.tsx",
|
||||
"sourceSha256": "2ea2c865a3e9817c140d3bf269a0c4f45d85a957f11b64d1a84e88926fe1b97a",
|
||||
"title": "toggles company order editing without selecting a company",
|
||||
"mutation": {
|
||||
"before": "text-left hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
|
||||
"after": "text-left hover:bg-accent hover:text-sidebar-accent-foreground",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(trigger?.classList).toContain(\"hover:bg-sidebar-accent\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "6927fb926814f3a97c2a4c93ff715eebb7b55c7b26cf78395352cd6cf72a1d94",
|
||||
"logSha256": "3a867b13b6c1a885838cda58afc327eac62f0eba9a60def7ec1d5d9b0a58b07b",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "cdfc31c2e7474765edcda5c384aedb266d4f7ba38a6593c6da5d08a3329c98f4",
|
||||
"logSha256": "e5d367e9396f285f008d50cc7745f3cbb4e49757bc887a4ec7847bf56cb0826c",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected \"inline-flex items-center whitespace-nowrap rounded-md text-sm font-medium transition-(--tp-color-background-color-border-color-box-shadow-opacity) disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-(length:--rad-3) aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive py-2 h-9 min-w-0 flex-1 justify-start gap-2 px-4 text-left hover:bg-accent hover:text-sidebar-accent-foreground has-[>svg]:px-4 dark:hover:bg-sidebar-accent dark:hover:text-sidebar-accent-foreground\" to contain \"hover:bg-sidebar-accent\"\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/SidebarCompanyMenu.test.tsx:431:32\n at runNextTicks (node:internal/process/task_queues:65:5)\n at listOnTimeout (node:internal/timers:567:9)\n at processTimers (node:internal/timers:541:7)\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "hover-foreground",
|
||||
"owner": "ui/src/components/SidebarCompanyMenu.tsx",
|
||||
"sourceSha256": "2ea2c865a3e9817c140d3bf269a0c4f45d85a957f11b64d1a84e88926fe1b97a",
|
||||
"title": "toggles company order editing without selecting a company",
|
||||
"mutation": {
|
||||
"before": "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground has-",
|
||||
"after": "hover:bg-sidebar-accent hover:text-foreground has-",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(trigger?.classList).toContain(\"hover:text-sidebar-accent-foreground\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "395cc772d310d912806b746111d7f557091468b89d37d178a6a8f941926d113b",
|
||||
"logSha256": "63ca60c22b27299275ea041bb23a009690f69e53a01857e34a63d222c0f790a5",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "7cee44772f8452a6a3236cdee1fd3b702a5b345bda5b14786125a5e63f4a7532",
|
||||
"logSha256": "260cb917636d6fa2a351a3dc1118c2c59fbca81f1d819e25ebc78468f6de5ca9",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected \"inline-flex items-center whitespace-nowrap rounded-md text-sm font-medium transition-(--tp-color-background-color-border-color-box-shadow-opacity) disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-(length:--rad-3) aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive py-2 h-9 min-w-0 flex-1 justify-start gap-2 px-4 text-left hover:bg-sidebar-accent hover:text-foreground has-[>svg]:px-4 dark:hover:bg-sidebar-accent dark:hover:text-sidebar-accent-foreground\" to contain \"hover:text-sidebar-accent-foreground\"\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/SidebarCompanyMenu.test.tsx:432:32\n at runNextTicks (node:internal/process/task_queues:65:5)\n at listOnTimeout (node:internal/timers:567:9)\n at processTimers (node:internal/timers:541:7)\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "dark-background",
|
||||
"owner": "ui/src/components/SidebarCompanyMenu.tsx",
|
||||
"sourceSha256": "2ea2c865a3e9817c140d3bf269a0c4f45d85a957f11b64d1a84e88926fe1b97a",
|
||||
"title": "toggles company order editing without selecting a company",
|
||||
"mutation": {
|
||||
"before": " dark:hover:bg-sidebar-accent ",
|
||||
"after": " dark:hover:bg-accent ",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(trigger?.classList).toContain(\"dark:hover:bg-sidebar-accent\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "e1c8a5b52bbd8abdeeebdc2257fff6c94ee10d92fd5933af3eb2ad9e73187086",
|
||||
"logSha256": "a11984915dd20c240e728db80d958100d62effb1d398de52e4b19116fc4df06a",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "6ef6c5847ced0672654141ddf703fe5da59b8e5698679983659f76b271836c34",
|
||||
"logSha256": "2289f05b931304d15b3e256a6b7c12d1d5b2377e938ca3d0bd2be14d6fa5ff93",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected \"inline-flex items-center whitespace-nowrap rounded-md text-sm font-medium transition-(--tp-color-background-color-border-color-box-shadow-opacity) disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-(length:--rad-3) aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive py-2 h-9 min-w-0 flex-1 justify-start gap-2 px-4 text-left hover:bg-sidebar-accent hover:text-sidebar-accent-foreground has-[>svg]:px-4 dark:hover:bg-accent dark:hover:text-sidebar-accent-foreground\" to contain \"dark:hover:bg-sidebar-accent\"\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/SidebarCompanyMenu.test.tsx:433:32\n at runNextTicks (node:internal/process/task_queues:65:5)\n at listOnTimeout (node:internal/timers:567:9)\n at processTimers (node:internal/timers:541:7)\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "dark-foreground",
|
||||
"owner": "ui/src/components/SidebarCompanyMenu.tsx",
|
||||
"sourceSha256": "2ea2c865a3e9817c140d3bf269a0c4f45d85a957f11b64d1a84e88926fe1b97a",
|
||||
"title": "toggles company order editing without selecting a company",
|
||||
"mutation": {
|
||||
"before": "dark:hover:text-sidebar-accent-foreground\"",
|
||||
"after": "dark:hover:text-foreground\"",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(trigger?.classList).toContain(\"dark:hover:text-sidebar-accent-foreground\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "b8dec44374759a2d23864d8773b523144f17251cc417c6ba3a5a01ad84c74d54",
|
||||
"logSha256": "38199b184a9191ec1f9690b5ee93a55372041e1bda5cccc283dd1606e5ff8c22",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "11c7a74f5e2910ad7245ce8dc6d0659d1c611c534fb0549b36f2a3e35fb3f5e3",
|
||||
"logSha256": "d5fa2d5d892bc50fda4e5129d56424e33cc6ad64038c8b00ccc9a2071e24024b",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected \"inline-flex items-center whitespace-nowrap rounded-md text-sm font-medium transition-(--tp-color-background-color-border-color-box-shadow-opacity) disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-(length:--rad-3) aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive py-2 h-9 min-w-0 flex-1 justify-start gap-2 px-4 text-left hover:bg-sidebar-accent hover:text-sidebar-accent-foreground has-[>svg]:px-4 dark:hover:bg-sidebar-accent dark:hover:text-foreground\" to contain \"dark:hover:text-sidebar-accent-foreground\"\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/SidebarCompanyMenu.test.tsx:434:32\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "create-copy",
|
||||
"owner": "ui/src/components/SidebarCompanyMenu.tsx",
|
||||
"sourceSha256": "2ea2c865a3e9817c140d3bf269a0c4f45d85a957f11b64d1a84e88926fe1b97a",
|
||||
"title": "toggles company order editing without selecting a company",
|
||||
"mutation": {
|
||||
"before": ">Create organization</span>",
|
||||
"after": ">New organization</span>",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(document.body.textContent).toContain(\"Create organization\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "094026d954d8a04e6c3f4a843905605b64087a7f1ffa32c0df6838da7b40abed",
|
||||
"logSha256": "dddb890d92209e044b1140d2438e28a02b814b8681fb96ab0e77e60c7026cf12",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "c4cb06631eace0851f3d31084c403ddb990f22f55f03096031361e195aba6211",
|
||||
"logSha256": "a7ecc001952a578b96aefa0a2c6f6ae7c87a01c8c64fb02102a50dad8c2f067a",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected 'AAcme LabsOrganizationsEditAAcme Labs\u2026' to contain 'Create organization'\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/SidebarCompanyMenu.test.tsx:445:39\n at runNextTicks (node:internal/process/task_queues:65:5)\n at processTimers (node:internal/timers:538:9)\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "legacy-create-copy",
|
||||
"owner": "ui/src/components/SidebarCompanyMenu.tsx",
|
||||
"sourceSha256": "2ea2c865a3e9817c140d3bf269a0c4f45d85a957f11b64d1a84e88926fe1b97a",
|
||||
"title": "toggles company order editing without selecting a company",
|
||||
"mutation": {
|
||||
"before": ">Create organization</span>",
|
||||
"after": ">Create organization Add company...</span>",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(document.body.textContent).not.toContain(\"Add company...\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "4b450bb9ee4240877a53fa40ba1279d27a2c5d2eefbbd1ec6d66739b5a142c9f",
|
||||
"logSha256": "53756ff97bc7913aab6c0a3bc303fd7151fb7cde78616841a3f9a07ef9e84d7b",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "93eb614e6f297f934fb4491e2b55a5d4a2f3216774b8d981a20d2b4a27b01a47",
|
||||
"logSha256": "220100c51d3b4e1ad9a020c6bb94af8f60b159cd1a5ef32cfcd67e04a5c77dfa",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected 'AAcme LabsOrganizationsEditAAcme Labs\u2026' not to contain 'Add company...'\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/SidebarCompanyMenu.test.tsx:446:43\n at runNextTicks (node:internal/process/task_queues:65:5)\n at processTimers (node:internal/timers:538:9)\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"priorEvidenceUnchanged": [
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-agentconfig-controls.json",
|
||||
"sha256": "cfb4357610beaa464cdb26848f74a7b8d967d6409c63dbd6821c92886a9cf980"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-agentconfig.md",
|
||||
"sha256": "ea6d5dfc8cedcd653edd55ca9d77568431413a351f4de5db77ca6ac8f22b051a"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appboundary-controls.json",
|
||||
"sha256": "bad49e7bc92dea919df6b980bfa45e7452984cf31a6fd4655b355ba0444ff9a6"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appboundary.md",
|
||||
"sha256": "cd6f173584db0d485004af6f85b1ce78fa65b19d8c6ef582b061f0d232c6c1ed"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appdetail-controls.json",
|
||||
"sha256": "7906fde0d62e14a7511b5cf45f864c9386a4c377922333eefc7f7e703c832f6a"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appdetail.md",
|
||||
"sha256": "715f23cd27502c92d0f5d1b83b91bcac03f254c73ab63b44181ae76939805229"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-attachments-controls.json",
|
||||
"sha256": "c4ff66a3226e1edafd286cad0ca45c9445795b46944cf70d606c59a754913f3a"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-attachments.md",
|
||||
"sha256": "d38715393c95306d10e871a5a2c9a32f105fa1452871cd7ad030d86dbbdb7416"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-controls.json",
|
||||
"sha256": "0d445f6f066032f2d9cd724525a8d7d2290246cbfeee1f6ab4b44818467af2a7"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-experimental-controls.json",
|
||||
"sha256": "9c72abee7ee1a937fdbd6ccee870320308bc7ce06b4fc1e338cd9bd3b0efba6b"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-experimental.md",
|
||||
"sha256": "93b7583a8ebba39dc97e390918fd62029955a00beda22756f55bd6374acc3737"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-inline-controls.json",
|
||||
"sha256": "af9d3f115e6e0518c2c0a2e11b8913e7aa82a35c848f114e6750884323601e17"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-inline.md",
|
||||
"sha256": "52d8e27970bd1c091ae7edf403b2331e921081da9198270df65ff779a8efc1bc"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-issuechat-controls.json",
|
||||
"sha256": "45d86fa901c8ab40bc3fe98d266e3ba1a7bbc93edb7bc2aae60ccd9bfa130c37"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-issuechat.md",
|
||||
"sha256": "15e84a553c5a468aea013941f68d3aa517bfb5a13ae296a90e1a39586f85de8e"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-issuedetail-controls.json",
|
||||
"sha256": "a56f183f1c6b940662db0c4bfb62457eda0cec453c2019b439ec716ed9d2a3e1"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-issuedetail.md",
|
||||
"sha256": "e137af5b991c936a167d6ad6f3c710b99688e939f839b163b203259fc998ded8"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-route-controls.json",
|
||||
"sha256": "0a72a7770ec749f2c0507a74d395e65d70b722d0b9d2a767a2c066a67ed46382"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-route.md",
|
||||
"sha256": "9b5e1543163d6c9d0958aa3e377a593ec458f6674ce1ddb2bf3ca158786f09c4"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-sidebar-controls.json",
|
||||
"sha256": "ae9f24746e67432cf6247c5da130b9c1bba46fc85112c0610d3f18545dfce326"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-sidebar.md",
|
||||
"sha256": "5e267441c43aa8375fa5c54edcbd2879428d657708be9a2ab372aa66e4792886"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-timeline-controls.json",
|
||||
"sha256": "6a86b07770f1cd8d758334fb61c46254197a7f533d24c056fc9a52c317488291"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-timeline.md",
|
||||
"sha256": "612dc3ec4c3d435888055ba20a7f28230ce89ea8b071b8c38d1ea2c147074a96"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-transcript-controls.json",
|
||||
"sha256": "9e4dbdc33806d6fcc912dc3aacc8691a77939e2ce2403032b2a8127c0e407e94"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-transcript.md",
|
||||
"sha256": "9e4ac8c92a3a9eca727c29a77ae428702d19ecdee0cab0e3dfcda0a36bf004db"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui.md",
|
||||
"sha256": "896b9928af85a4c7d588dfca93484980aadb238bd79d8142e671c62f0b191fa8"
|
||||
}
|
||||
],
|
||||
"ownerRestoredToBaseGitBytes": true,
|
||||
"productionLinesChanged": 0
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
# Test audit, Round 7 UI — Company menu opening follow-up
|
||||
|
||||
This separate packet removes **1 registered executions, 1 rendered scenarios and 28 net test lines** from `ui/src/components/SidebarCompanyMenu.test.tsx`. It adds no helper and changes no production lines. Audit base: `2e76f5157240ee8b2d42adbdcd4c345aea07c013`. All prior committed proof remains byte-identical. Registration/render savings are per complete-suite invocation; no measured runtime or CI-speed claim is made. A service-worker retirement counts only initializer setup, never a render.
|
||||
|
||||
## Exact retirement map
|
||||
|
||||
| Retired registration | Keeper | Exact observations migrated |
|
||||
|---|---|---|
|
||||
| `uses company-centric create copy without the chat flag` | `toggles company order editing without selecting a company` | expect(trigger?.classList).toContain("px-4");; expect(trigger?.classList).toContain("has-[>svg]:px-4");; expect(trigger?.classList).toContain("hover:bg-sidebar-accent");; expect(trigger?.classList).toContain("hover:text-sidebar-accent-foreground");; expect(trigger?.classList).toContain("dark:hover:bg-sidebar-accent");; expect(trigger?.classList).toContain("dark:hover:text-sidebar-accent-foreground");; expect(trigger?.classList).not.toContain("hover:bg-background");; expect(trigger?.classList).not.toContain("dark:hover:bg-background");; expect(trigger?.classList).not.toContain("dark:hover:bg-accent/50");; expect(document.body.textContent).toContain("Create organization");; expect(document.body.textContent).not.toContain("Add company..."); |
|
||||
|
||||
The original fresh QueryClient/provider/root setup, two flushes, trigger query and presence assertion match exactly. Both pointerdown/click opening statements and following flush also match. All nine original trigger-class checks move before opening; both Create organization/Add company copy checks move after opening and before Edit. The keeper retains order editing, reorder-button/row guards and no selection/navigation assertions. Existing health-enabled actions, sign-out, loading/error, selection and other menu cases stay distinct. The six exact trigger-class mutations cover the inset and light/dark hover styling behaviors; the three negative legacy-color guards also remain in the keeper. Adding a conflicting class was rejected as mutation evidence because tailwind-merge removed the required positive token before the negative guard. No token or production style change is included.
|
||||
|
||||
The verifier requires matching setup statements, enclosing hooks and explicit teardown where present. It reconstructs candidate source solely from the declared registrations/assertion migrations and requires exact byte equality plus full-program AST equality outside those edits. Existing shared variable bindings, mock arguments and provider/component inputs remain the same. No other fixture, helper, action order, wait, assertion strength, timer or cleanup changes. Default CI includes the file in `@paperclipai/ui` under `general-workspaces-a`, once across its two file shards, with no workflow/config change.
|
||||
|
||||
## Complete owner-file results
|
||||
|
||||
| Run | Registered | Passed | Failed | Skipped |
|
||||
|---|---:|---:|---:|---:|
|
||||
| Baseline | 16 | 16 | 0 | 0 |
|
||||
| Candidate | 15 | 15 | 0 | 0 |
|
||||
|
||||
From `ui/`: `pnpm exec vitest run src/components/SidebarCompanyMenu.test.tsx`.
|
||||
|
||||
All 8 separately selected positive controls passed. All 8 distinct production-owner regressions failed at intended retained/migrated assertions, not setup, timeout or another guard:
|
||||
|
||||
| Regression | Intended guard |
|
||||
|---|---|
|
||||
| trigger-inset | `expect(trigger?.classList).toContain("px-4")` |
|
||||
| icon-inset | `expect(trigger?.classList).toContain("has-[>svg]:px-4")` |
|
||||
| hover-background | `expect(trigger?.classList).toContain("hover:bg-sidebar-accent")` |
|
||||
| hover-foreground | `expect(trigger?.classList).toContain("hover:text-sidebar-accent-foreground")` |
|
||||
| dark-background | `expect(trigger?.classList).toContain("dark:hover:bg-sidebar-accent")` |
|
||||
| dark-foreground | `expect(trigger?.classList).toContain("dark:hover:text-sidebar-accent-foreground")` |
|
||||
| create-copy | `expect(document.body.textContent).toContain("Create organization")` |
|
||||
| legacy-create-copy | `expect(document.body.textContent).not.toContain("Add company...")` |
|
||||
|
||||
Exactly one production owner changed per control, and every owner was restored byte for byte after each mutation and checked against pinned Git bytes. Literal keeper-name filters are escaped; unselected cases are not full-suite evidence. The initial first-install receipt verifier mistook emit( for it( and rejected its receipt despite the intended test failure. The declaration-boundary matcher was corrected and that control rerun; the rejected verifier attempt supplies no accepted evidence.
|
||||
|
||||
[Controls JSON](2026-10-12-test-audit-r7-ui-company-menu-controls.json) preserves source/owner hashes, exact before/after migrations, matched setup and variable-binding proof, complete-file run/log digests, intended assertion failures and restoration checks. Temporary raw scripts/logs are identified by digests rather than committed in full.
|
||||
|
||||
The earlier broad local `pnpm test:run` was intentionally stopped before completion and is not claimed as passed. These separate focused packets precede delivery-head replay and full CI. This packet includes no push, rebase, PR or merge.
|
||||
@@ -0,0 +1,692 @@
|
||||
{
|
||||
"base": "e868e6645ce0d598d756d3458f0b3d71afd6db4a",
|
||||
"scope": [
|
||||
"ui/src/pages/InviteLanding.test.tsx",
|
||||
"ui/src/pages/Agents.test.tsx",
|
||||
"ui/src/components/Layout.test.tsx"
|
||||
],
|
||||
"testLinesRemoved": 364,
|
||||
"productionLinesChanged": 0,
|
||||
"registeredInvocationsRemoved": 1,
|
||||
"sourceHelperCallsExpanded": 60,
|
||||
"speedClaim": null,
|
||||
"expansionNormalization": [
|
||||
"AST locations",
|
||||
"comments",
|
||||
"raw literal formatting",
|
||||
"whitespace-only JSX text"
|
||||
],
|
||||
"expansionVerifierSha256": "c97239d6b978cc11bb2f8ed11e0521ac107c37c6af5183dbd934d58b94418b3c",
|
||||
"expansions": [
|
||||
{
|
||||
"file": "ui/src/pages/InviteLanding.test.tsx",
|
||||
"originalSha": "2283067e52a3409f4c1a21e017e273649989559e7013a0d1442ebea268989bdd",
|
||||
"candidateSha": "84ab29d3d382710df5d39d8e6d84fb2cf916d10e2470e6432d54ac2875a55153",
|
||||
"expansions": 18,
|
||||
"wholeProgramAstEqualOutsideMigration": true,
|
||||
"migration": null,
|
||||
"helperSync": true,
|
||||
"parameterBindingArguments": [
|
||||
"root",
|
||||
"queryClient"
|
||||
],
|
||||
"freshJsxPerCall": true,
|
||||
"expandedAstSha": "a95408adf3b302b35d13a5a40d1b0cddacff4232bff02629a275f63698b3f489"
|
||||
},
|
||||
{
|
||||
"file": "ui/src/pages/Agents.test.tsx",
|
||||
"originalSha": "f7a84d1d31119880d6b11dc956d3121930ba4e92a2df7832d32676fc48cb2313",
|
||||
"candidateSha": "e2ab9c0de428585bee37b40df1ee6c4a3c823882582d006abadbfedbdd3e50ff",
|
||||
"expansions": 16,
|
||||
"wholeProgramAstEqualOutsideMigration": true,
|
||||
"migration": {
|
||||
"retired": "uses the built-in agents route segment as the built-in filter",
|
||||
"keeper": "shows and filters built-in agents when the experimental flag is enabled",
|
||||
"copiedExactRetiredSetup": true,
|
||||
"migratedCountGuard": "1 agent",
|
||||
"originalKeeperOtherAssertionsUnchanged": true
|
||||
},
|
||||
"helperSync": true,
|
||||
"parameterBindingArguments": [
|
||||
"root",
|
||||
"queryClient"
|
||||
],
|
||||
"freshJsxPerCall": true,
|
||||
"expandedAstSha": "2b0ff05182aa4cee5f94040fcff0321cb4ba7bce0e6a4d08bbaccf65e38873bb"
|
||||
},
|
||||
{
|
||||
"file": "ui/src/components/Layout.test.tsx",
|
||||
"originalSha": "d522929332ccbd413d56d5c9b7d7cd820344b58d6baa17b70002ecd387039093",
|
||||
"candidateSha": "89b6c599f2cecd570831e1a5d3d673bc1188052ca8eeedb6013892d25491f791",
|
||||
"expansions": 26,
|
||||
"wholeProgramAstEqualOutsideMigration": true,
|
||||
"migration": null,
|
||||
"helperSync": true,
|
||||
"parameterBindingArguments": [
|
||||
"root",
|
||||
"queryClient"
|
||||
],
|
||||
"freshJsxPerCall": true,
|
||||
"expandedAstSha": "150995d2bb95bb3c7afa57ce23f38b664f518c2fe7ed1ca039475f24fb6f6f9f"
|
||||
}
|
||||
],
|
||||
"runs": [
|
||||
{
|
||||
"label": "owners baseline",
|
||||
"jsonSha256": "8995c66ecc3951722950526f9c3d1b6de551b8ac6cc153576d1315c43e0c7a5c",
|
||||
"cases": 71,
|
||||
"passed": 71,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"files": [
|
||||
{
|
||||
"path": "ui/src/pages/Agents.test.tsx",
|
||||
"status": "passed",
|
||||
"cases": 21
|
||||
},
|
||||
{
|
||||
"path": "ui/src/pages/InviteLanding.test.tsx",
|
||||
"status": "passed",
|
||||
"cases": 18
|
||||
},
|
||||
{
|
||||
"path": "ui/src/components/Layout.test.tsx",
|
||||
"status": "passed",
|
||||
"cases": 32
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "siblings baseline",
|
||||
"jsonSha256": "e4326b65ac0c85207df2c0a055a5ca7c34138fead744cf9ebd7c9ea060f27291",
|
||||
"cases": 79,
|
||||
"passed": 79,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"files": [
|
||||
{
|
||||
"path": "ui/src/hooks/useCompanyInviteAccess.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 10
|
||||
},
|
||||
{
|
||||
"path": "ui/src/lib/company-selection.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 11
|
||||
},
|
||||
{
|
||||
"path": "ui/src/lib/shell-navigation.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 6
|
||||
},
|
||||
{
|
||||
"path": "ui/src/components/ActiveAgentsPanel.test.tsx",
|
||||
"status": "passed",
|
||||
"cases": 8
|
||||
},
|
||||
{
|
||||
"path": "ui/src/components/PluginAppShellOverlays.test.tsx",
|
||||
"status": "passed",
|
||||
"cases": 6
|
||||
},
|
||||
{
|
||||
"path": "ui/src/components/SidebarAgents.test.tsx",
|
||||
"status": "passed",
|
||||
"cases": 26
|
||||
},
|
||||
{
|
||||
"path": "ui/src/components/SidebarShell.test.tsx",
|
||||
"status": "passed",
|
||||
"cases": 9
|
||||
},
|
||||
{
|
||||
"path": "ui/src/components/access/InvitesSection.test.tsx",
|
||||
"status": "passed",
|
||||
"cases": 3
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "owners candidate",
|
||||
"jsonSha256": "3bf91a48289f6db06c9ca0fdaf552866c39cebc20dec89602fb2ad8faaceb498",
|
||||
"cases": 70,
|
||||
"passed": 70,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"files": [
|
||||
{
|
||||
"path": "ui/src/pages/Agents.test.tsx",
|
||||
"status": "passed",
|
||||
"cases": 20
|
||||
},
|
||||
{
|
||||
"path": "ui/src/pages/InviteLanding.test.tsx",
|
||||
"status": "passed",
|
||||
"cases": 18
|
||||
},
|
||||
{
|
||||
"path": "ui/src/components/Layout.test.tsx",
|
||||
"status": "passed",
|
||||
"cases": 32
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "all complete candidate",
|
||||
"jsonSha256": "d17ff01fc3d46e1679832f3d589a4907cbed8be3f5012ae7e7079a93bfb5a118",
|
||||
"cases": 149,
|
||||
"passed": 149,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"files": [
|
||||
{
|
||||
"path": "ui/src/hooks/useCompanyInviteAccess.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 10
|
||||
},
|
||||
{
|
||||
"path": "ui/src/pages/Agents.test.tsx",
|
||||
"status": "passed",
|
||||
"cases": 20
|
||||
},
|
||||
{
|
||||
"path": "ui/src/pages/InviteLanding.test.tsx",
|
||||
"status": "passed",
|
||||
"cases": 18
|
||||
},
|
||||
{
|
||||
"path": "ui/src/components/ActiveAgentsPanel.test.tsx",
|
||||
"status": "passed",
|
||||
"cases": 8
|
||||
},
|
||||
{
|
||||
"path": "ui/src/components/Layout.test.tsx",
|
||||
"status": "passed",
|
||||
"cases": 32
|
||||
},
|
||||
{
|
||||
"path": "ui/src/components/PluginAppShellOverlays.test.tsx",
|
||||
"status": "passed",
|
||||
"cases": 6
|
||||
},
|
||||
{
|
||||
"path": "ui/src/components/SidebarAgents.test.tsx",
|
||||
"status": "passed",
|
||||
"cases": 26
|
||||
},
|
||||
{
|
||||
"path": "ui/src/components/SidebarShell.test.tsx",
|
||||
"status": "passed",
|
||||
"cases": 9
|
||||
},
|
||||
{
|
||||
"path": "ui/src/lib/company-selection.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 11
|
||||
},
|
||||
{
|
||||
"path": "ui/src/lib/shell-navigation.test.ts",
|
||||
"status": "passed",
|
||||
"cases": 6
|
||||
},
|
||||
{
|
||||
"path": "ui/src/components/access/InvitesSection.test.tsx",
|
||||
"status": "passed",
|
||||
"cases": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"mutations": [
|
||||
{
|
||||
"slug": "builtin-filter",
|
||||
"owner": "ui/src/pages/Agents.tsx",
|
||||
"title": "shows and filters built-in agents when the experimental flag is enabled",
|
||||
"sourceSha": "a734799d3b015ddc04424754ff30eb2eb872db66e8847c4603132093fbb5e9b2",
|
||||
"replacements": 1,
|
||||
"mutation": {
|
||||
"before": "if (tab === \"builtin\") return builtInAgentIds.has(a.id);",
|
||||
"after": "if (tab === \"builtin\") return true;"
|
||||
},
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"status": "passed",
|
||||
"jsonSha256": "9189086e19c4ca525e7c8692bfc3778bdb273647ee2eae0d1c9258c3904f68e6",
|
||||
"logSha256": "91eb9ad0112c20347e1229c9d40002be1a6fc7f3c6c2b15ff82ba9fb8a84621c"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"status": "failed",
|
||||
"jsonSha256": "c3710d64d3205aff35c8645d4c5675c49d2d1e28ac6f6bd3c2cfb49231386842",
|
||||
"logSha256": "3c0ec61eae54edafcce43bfed5d791aa0d65ff8e6c99969a3e378e537942c8bf",
|
||||
"intendedFailure": "AssertionError: expected 'AllActivePausedErrorBuilt-inNew Agent\u2026' to contain '1 agent'"
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "invite-aria-invalid",
|
||||
"owner": "ui/src/pages/InviteLanding.tsx",
|
||||
"title": "renders invite auth errors in an alert region referenced by the inputs",
|
||||
"sourceSha": "626dc7c372a74ff436f1f96f675ecf55bd0b2ae60107ec61bc88cec8c6fefe18",
|
||||
"replacements": 3,
|
||||
"mutation": {
|
||||
"before": "aria-invalid={authFeedback?.tone === \"error\" ? true : undefined}",
|
||||
"after": "aria-invalid={undefined}"
|
||||
},
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"status": "passed",
|
||||
"jsonSha256": "f5401b7b6c33dea587d00dedb8fe64c3baaa04f45fcb54ebd3225b0339de4291",
|
||||
"logSha256": "802bc10c23fbeb70cae9effbef913145a90a28dd893550be3c6941ffbd1d4396"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"status": "failed",
|
||||
"jsonSha256": "58d01e3723ff05867f87f82e2fa857d4d1d3d5f81dd50d04603d7da3b148c060",
|
||||
"logSha256": "c90dcb374262c2caf2ca5a27069a2cbe5a2a1b4615df05d82a4e82e129e58080",
|
||||
"intendedFailure": "AssertionError: expected null to be 'true' // Object.is equality"
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "settings-sidebar",
|
||||
"owner": "ui/src/components/Layout.tsx",
|
||||
"title": "replaces the app sidebar with settings navigation on Streamlined settings routes",
|
||||
"sourceSha": "4c236e0330ed4946572af9528f27d24c305bc3e73473814e921017199d4afa8a",
|
||||
"replacements": 1,
|
||||
"mutation": {
|
||||
"before": "const sharedSecondarySidebar = isCompanySettingsRoute ? (",
|
||||
"after": "const sharedSecondarySidebar = false ? ("
|
||||
},
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"status": "passed",
|
||||
"jsonSha256": "c4cba1779379171ad2d0fc234e699944118ab453f3f87c4547d92e688d3f64ef",
|
||||
"logSha256": "5e6de08a8cda51850e9e237a76d993ceff3e32677ef38faaf2bffd0d40c6cf10"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"status": "failed",
|
||||
"jsonSha256": "a0cdaa7f1233d4f88d6abd92f61984343f41b27e2723b8ce28b16a8c97624366",
|
||||
"logSha256": "83b0ab380a65c7f9ec69f8ec36132dbafb6ef9cc2c4df220b20415144244eab3",
|
||||
"intendedFailure": "AssertionError: expected 'Skip to Main ContentPaperclipCompany \u2026' to contain 'Company settings sidebar'"
|
||||
}
|
||||
}
|
||||
],
|
||||
"caseLedger": [
|
||||
{
|
||||
"file": "ui/src/pages/Agents.test.tsx",
|
||||
"cases": [
|
||||
{
|
||||
"title": "omits the action bar from streamlined agent list rows",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "omits the action bar from production agent list rows",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "shows the configured model beside the adapter on the all agents page",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "switches between the preserved list and the interactive org chart with icon buttons",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "gives mobile agent names the full row width after the leading status indicator",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "uses the built-in agents route segment as the built-in filter",
|
||||
"decision": "C",
|
||||
"evidence": "Exact keeper retains fixture/count plus all stronger assertions"
|
||||
},
|
||||
{
|
||||
"title": "shows effective environment and sandbox provider beside agents",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "uses configured names for local-driver environments",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "reserves the environment column while environment metadata is loading",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "hides the environment column when there is only one configured environment",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "hides the environment column when environments are experimentally disabled",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "uses the instance default environment unless the agent overrides it",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "falls back to the raw sandbox provider config when capabilities omit a display name",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "does not show environment filter or grouping controls yet",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "hides built-in agent surfaces while the experimental flag is disabled",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "shows and filters built-in agents when the experimental flag is enabled",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "gives list-view rows a fixed-width title so meta columns align (PAP-86)",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "omits star and leave/join actions from streamlined agent index list and org views",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "omits star and leave/join actions from production agent index list and org views",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "does not dim left-membership agent names on mobile",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "keeps invalid-org-chain agents visible with a warning marker",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "ui/src/pages/InviteLanding.test.tsx",
|
||||
"cases": [
|
||||
{
|
||||
"title": "keeps agent-invite onboarding on legacy adapters",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "defaults invite auth to account creation and guides existing users back to sign in",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "carries password-manager metadata and a11y attributes on the invite auth form",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "renders invite auth errors in an alert region referenced by the inputs",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "turns invalid sign-in responses into a clear invite-specific message",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "auto-accepts the invite after account creation and redirects into the company",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "shows the pending approval page with the company icon and non-clickable access instructions",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "auto-completes a previously accepted human invite after sign-in",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "asks unauthenticated users to sign in before completing an accepted human invite",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "redirects straight to the company after sign-in when the user already has access",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "re-reads membership for the account that just signed in",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "re-reads membership on mount for an already signed-in account",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "keeps the pending invite token when the session has lapsed",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "still reads the shared list as membership on a local_trusted instance",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "shows invite details instead of auto-redirecting for signed-in existing members",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "falls back to the generated company icon when the invite logo fails to load",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "normalizes the shared company cache envelope before checking membership",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "waits for the membership check before showing invite acceptance to signed-in users",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "ui/src/components/Layout.test.tsx",
|
||||
"cases": [
|
||||
{
|
||||
"title": "does not render the deployment explainer in the shared layout",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "scopes the Streamlined task-detail surface while preserving balanced horizontal gutters",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "collapses atomically when the pointer is still over the sidebar (no re-peek) \u2014 PAP-10676",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "opens the peek when hovering a collapsed rail (positive control for the hover sim)",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "replaces the app sidebar with settings navigation on Streamlined settings routes",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "keeps the global sidebar beside legacy settings navigation when Streamlined UI is off",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "renders a mobile company settings selector on company settings routes",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "replaces the company nav on instance settings routes",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "replaces the company nav with the shared settings sidebar on /PAP/company/export",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "replaces the company nav with the shared settings sidebar on /PAP/company/import",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "keeps the company nav beside Apps navigation on legacy tools routes",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "mounts the Apps secondary sidebar regardless of the retired experimental flag",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "keeps the Apps sidebar on the M8 advanced-setup tabs",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "keeps the Apps sidebar on legacy developer tabs behind the Advanced door",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "keeps the Apps sidebar on the browse surface",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "keeps the Apps sidebar on the connections surface",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "keeps the Apps sidebar on the vercel-connect surface",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "keeps the Apps sidebar on the review surface",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "keeps the Apps sidebar on the chat surface",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "keeps the Apps sidebar on the gateways list and detail routes",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "uses the app connection sidebar on app detail routes",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "uses the app detail sidebar on not-connected app routes",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "keeps global navigation beside Skills, Agent, and Routine details",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "keeps global navigation with agent configuration navigation in the legacy shell",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "keeps the global rail beside Skills navigation in the legacy shell",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "keeps Agent and Routine collection routes in global navigation",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "renders a route-scoped plugin sidebar for a matching plugin page route",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "keeps the route-scoped plugin sidebar on nested plugin page routes",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "uses the route company context for plugin route sidebars on the first render",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "keeps the normal company sidebar when a plugin page route is ambiguous",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "clips horizontal overflow on the mobile layout root so the viewport can't scroll sideways",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
},
|
||||
{
|
||||
"title": "clips overflow on the desktop layout root",
|
||||
"decision": "R",
|
||||
"evidence": "Whole-program expansion retains original assertions and action order outside the one recorded keeper migration"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"rawEvidenceAvailability": "Raw verifiers and run logs are temporary local audit packets; the committed report/JSON retain accepted decisions and digests, not complete raw payloads.",
|
||||
"helperCleanupNetLinesRemoved": 320,
|
||||
"duplicateRetirementNetLinesRemoved": 44
|
||||
}
|
||||
@@ -0,0 +1,306 @@
|
||||
{
|
||||
"audit": {
|
||||
"file": "ui/src/pages/InstanceExperimentalSettings.test.tsx",
|
||||
"base": "e3effbb9e5c66b838f67fd487987c8bf1007e413",
|
||||
"originalSha256": "52dac85dd5b2ac621da8b25a73a343a15068fde818e64d59d5cf22ab9eee1dd0",
|
||||
"candidateSha256": "4a1047181ad420553d9c9470f59f5df4287d9e37b06fc11cb4658625a758df65",
|
||||
"allOtherProgramAstUnchanged": true,
|
||||
"allOtherSourceBytesUnchanged": true,
|
||||
"newHelpers": 0,
|
||||
"registeredInvocationsRemoved": 2,
|
||||
"rootRendersRemoved": 2,
|
||||
"netTestLinesRemoved": 10,
|
||||
"migrations": [
|
||||
{
|
||||
"retired": "does not render the Pipelines experimental setting for now",
|
||||
"keeper": "does not render the Conference Room Chat experimental setting for now",
|
||||
"exactSetupStatements": 2,
|
||||
"sameEnclosingHooks": true,
|
||||
"exactCleanupStatements": 0,
|
||||
"migratedGuards": [
|
||||
"expect(headings).not.toContain(\"Pipelines\");",
|
||||
"expect(container.querySelector('button[aria-label=\"Toggle pipelines experimental setting\"]')).toBeNull();"
|
||||
],
|
||||
"exactDuplicateGuardAlreadyKept": [],
|
||||
"registeredInvocationsRemoved": 1,
|
||||
"rootRendersRemoved": 1
|
||||
},
|
||||
{
|
||||
"retired": "shows the cutoff-copy for the worktree run-execution toggle when off",
|
||||
"keeper": "renders and patches the worktree run-execution toggle when in a worktree",
|
||||
"exactSetupStatements": 2,
|
||||
"sameEnclosingHooks": true,
|
||||
"exactCleanupStatements": 0,
|
||||
"migratedGuards": [
|
||||
"expect(container.textContent).toContain(\n \"Only tasks created after enabling will run automatically\",\n );",
|
||||
"expect(container.textContent).toContain(\"Toggling off and on resets the cutoff.\");",
|
||||
"expect(container.textContent).not.toContain(\"Running tasks created after\");",
|
||||
"expect(container.textContent).not.toContain(\"Execution is suppressed\");"
|
||||
],
|
||||
"exactDuplicateGuardAlreadyKept": [],
|
||||
"registeredInvocationsRemoved": 1,
|
||||
"rootRendersRemoved": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"verifierSha256": "084bdbc359e510397ef64daeb24e259efbc62c8b5d2c56d3e09d7f2534f155aa",
|
||||
"mutationVerifierSha256": "ca8463047109d38a447d93fb94a19bb8efe9b1df440e0abf91ab31a8c0a358a2",
|
||||
"runs": [
|
||||
{
|
||||
"kind": "baseline",
|
||||
"total": 55,
|
||||
"passed": 55,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"jsonSha256": "77f407f50f91bcdacb518c7b87b6dc5b47b9161a9bc49bfab32a6ee228351d38",
|
||||
"logSha256": "a92310f5aab6de68b137ab9f6d8348fc0fe8640e37740ec0bfb493b3017edeb6"
|
||||
},
|
||||
{
|
||||
"kind": "candidate",
|
||||
"total": 53,
|
||||
"passed": 53,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"jsonSha256": "09e8de86d6b8fcbe9fb5fb4c74ea6a5fb57c1135763c5b6054232409435a6bc3",
|
||||
"logSha256": "099ac5b8f1f678b23518f93833cf2924c4dd2833700f7f6a009f1065fb573bf3"
|
||||
}
|
||||
],
|
||||
"mutations": [
|
||||
{
|
||||
"slug": "pipelines-heading",
|
||||
"owner": "ui/src/pages/InstanceExperimentalSettings.tsx",
|
||||
"sourceSha256": "946dd94d28db014fe2dbfc0bb8d4c5a4b96c3face7fca7a067789119abe76570",
|
||||
"title": "does not render the Conference Room Chat experimental setting for now",
|
||||
"mutation": {
|
||||
"before": " {SHOW_CONFERENCE_ROOM_EXPERIMENTAL_SETTING ? (",
|
||||
"after": " <section><h2>Pipelines</h2></section>\n {SHOW_CONFERENCE_ROOM_EXPERIMENTAL_SETTING ? (",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(headings).not.toContain(\"Pipelines\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "7250f54890e55f4ad28063a359430027e325435ba39877b46b0d1a052196b8e5",
|
||||
"logSha256": "f9a5178102546567b9cd25aed172c9f25496cfb250af226edb0721e5293792ef",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "a1bfbd98a6faf2364a061415d99e76799b6d23ed8627c5e5e27de64901e6b108",
|
||||
"logSha256": "d498153df7fd34e0fe41d1c8996cc867553b949b266fe6e83bd1c72b76a0a6a2",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected [ 'Experimental features', \u2026(3) ] to not include 'Pipelines'\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:2077:15)\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:1944:14)\n at Proxy.methodWrapper (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/chai@6.3.0/node_modules/chai/index.js:1737:25)\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/pages/InstanceExperimentalSettings.test.tsx:319:26\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "pipelines-toggle",
|
||||
"owner": "ui/src/pages/InstanceExperimentalSettings.tsx",
|
||||
"sourceSha256": "946dd94d28db014fe2dbfc0bb8d4c5a4b96c3face7fca7a067789119abe76570",
|
||||
"title": "does not render the Conference Room Chat experimental setting for now",
|
||||
"mutation": {
|
||||
"before": " {SHOW_CONFERENCE_ROOM_EXPERIMENTAL_SETTING ? (",
|
||||
"after": " <button aria-label=\"Toggle pipelines experimental setting\" />\n {SHOW_CONFERENCE_ROOM_EXPERIMENTAL_SETTING ? (",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(container.querySelector('button[aria-label=\"Toggle pipelines experimental setting\"]')).toBeNull()",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "a33d4d20281ca29d7e8ed3e27d4e7d5426053a5d0e2d95e1805dc33a0ae488fb",
|
||||
"logSha256": "26e0d1406c59c0ea2ef2c24b94df8a26c3a64ee31ba8a625e8a1079389687b26",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "7fc3b1c7422ea1f814176df613b12f3250ad66816b25ce78b0c7a6dc034c45b9",
|
||||
"logSha256": "09c205c0b6bb1b99738b5d9ae609402c623d2e9880502dc6ea07ee406a020c8b",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected <button \u2026(1)></button> to be null\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/pages/InstanceExperimentalSettings.test.tsx:320:99\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "cutoff-copy",
|
||||
"owner": "ui/src/pages/InstanceExperimentalSettings.tsx",
|
||||
"sourceSha256": "946dd94d28db014fe2dbfc0bb8d4c5a4b96c3face7fca7a067789119abe76570",
|
||||
"title": "renders and patches the worktree run-execution toggle when in a worktree",
|
||||
"mutation": {
|
||||
"before": "Only tasks created after enabling will run automatically",
|
||||
"after": "The cutoff copy is missing",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(container.textContent).toContain(",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "92c1be77e6c65655e99e26189954c5143e8c248be26f32d1b76257b97db781e4",
|
||||
"logSha256": "dd36eab0fb20ae3a948e91625ef5e8c29c7a0451623d6b50f91c89881f43b16a",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "ebdd5d754e22071cbc50f1246b16b38fc14349885f0f77da2f257e208b780211",
|
||||
"logSha256": "145903c50a5cb4eb8185d3c160f986a470c068259c54c74d7c05961df6cb828d",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected 'ExperimentalOpt into features that ar\u2026' to contain 'Only tasks created after enabling wil\u2026'\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/pages/InstanceExperimentalSettings.test.tsx:593:35\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "reset-copy",
|
||||
"owner": "ui/src/pages/InstanceExperimentalSettings.tsx",
|
||||
"sourceSha256": "946dd94d28db014fe2dbfc0bb8d4c5a4b96c3face7fca7a067789119abe76570",
|
||||
"title": "renders and patches the worktree run-execution toggle when in a worktree",
|
||||
"mutation": {
|
||||
"before": "Toggling off and on resets the cutoff.",
|
||||
"after": "The reset copy is missing",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(container.textContent).toContain(\"Toggling off and on resets the cutoff.\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "08e815451edaa0b5a916e5027dfb0cb72a723dfde98e234873404a4f9cd4ccce",
|
||||
"logSha256": "ba51c2a1cda7f0cc33a686e28fc9fc405737107133c3beea98fcf1c3696bd5c4",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "21d1d20cb6fd05663c4decd09baeb5533d2147017a7bbb14eee0657f295953b0",
|
||||
"logSha256": "c0efad555c6819cd6e7c91692ac64521de7f1045be075ca3330cc6dd1c43df84",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected 'ExperimentalOpt into features that ar\u2026' to contain 'Toggling off and on resets the cutoff.'\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/pages/InstanceExperimentalSettings.test.tsx:596:35\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "armed-banner",
|
||||
"owner": "ui/src/pages/InstanceExperimentalSettings.tsx",
|
||||
"sourceSha256": "946dd94d28db014fe2dbfc0bb8d4c5a4b96c3face7fca7a067789119abe76570",
|
||||
"title": "renders and patches the worktree run-execution toggle when in a worktree",
|
||||
"mutation": {
|
||||
"before": " {worktreeRunExecutionState.kind === \"armed\" ? (",
|
||||
"after": " <span>Running tasks created after</span>\n {worktreeRunExecutionState.kind === \"armed\" ? (",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(container.textContent).not.toContain(\"Running tasks created after\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "c9a437b67ada80258549e3e55e2839eb9247dca4e28eb31de8d5f5cea62aeae9",
|
||||
"logSha256": "4b4b08da42e012356f839eee58b1c22d7b897d5055171e9167dfc54e29d314b7",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "53682bf5e687c68851723b3729a8f0979c0e68800186b70cf5d9c4a2e1cc8f04",
|
||||
"logSha256": "7accc209bfd5438d9772a1d2f3d121b976f0579af35853d8367c527c80ada5af",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected 'ExperimentalOpt into features that ar\u2026' not to contain 'Running tasks created after'\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/pages/InstanceExperimentalSettings.test.tsx:598:39\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "fail-closed",
|
||||
"owner": "ui/src/pages/InstanceExperimentalSettings.tsx",
|
||||
"sourceSha256": "946dd94d28db014fe2dbfc0bb8d4c5a4b96c3face7fca7a067789119abe76570",
|
||||
"title": "renders and patches the worktree run-execution toggle when in a worktree",
|
||||
"mutation": {
|
||||
"before": " {worktreeRunExecutionState.kind === \"fail_closed\" ? (",
|
||||
"after": " <span>Execution is suppressed</span>\n {worktreeRunExecutionState.kind === \"fail_closed\" ? (",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(container.textContent).not.toContain(\"Execution is suppressed\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "0dccde3c027394a05076bc86035b085a2f420f102f65c234e6f536aaaf452e5e",
|
||||
"logSha256": "9db8b2995432fdd99a941e894df0148b4fe83d12a20a86d87acc594b874c8005",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "fbc4edb913cba46818b5d9dd073a1b02d804e07f8a50e49bd180e5ab6c86b609",
|
||||
"logSha256": "4f2dc5d037bea144ce679f1800079de085b153040ea553bae985bdc765e670fa",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected 'ExperimentalOpt into features that ar\u2026' not to contain 'Execution is suppressed'\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/pages/InstanceExperimentalSettings.test.tsx:599:39\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"priorEvidenceUnchanged": [
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appboundary-controls.json",
|
||||
"sha256": "bad49e7bc92dea919df6b980bfa45e7452984cf31a6fd4655b355ba0444ff9a6"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appboundary.md",
|
||||
"sha256": "cd6f173584db0d485004af6f85b1ce78fa65b19d8c6ef582b061f0d232c6c1ed"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appdetail-controls.json",
|
||||
"sha256": "7906fde0d62e14a7511b5cf45f864c9386a4c377922333eefc7f7e703c832f6a"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appdetail.md",
|
||||
"sha256": "715f23cd27502c92d0f5d1b83b91bcac03f254c73ab63b44181ae76939805229"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-attachments-controls.json",
|
||||
"sha256": "c4ff66a3226e1edafd286cad0ca45c9445795b46944cf70d606c59a754913f3a"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-attachments.md",
|
||||
"sha256": "d38715393c95306d10e871a5a2c9a32f105fa1452871cd7ad030d86dbbdb7416"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-controls.json",
|
||||
"sha256": "0d445f6f066032f2d9cd724525a8d7d2290246cbfeee1f6ab4b44818467af2a7"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-route-controls.json",
|
||||
"sha256": "0a72a7770ec749f2c0507a74d395e65d70b722d0b9d2a767a2c066a67ed46382"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-route.md",
|
||||
"sha256": "9b5e1543163d6c9d0958aa3e377a593ec458f6674ce1ddb2bf3ca158786f09c4"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-sidebar-controls.json",
|
||||
"sha256": "ae9f24746e67432cf6247c5da130b9c1bba46fc85112c0610d3f18545dfce326"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-sidebar.md",
|
||||
"sha256": "5e267441c43aa8375fa5c54edcbd2879428d657708be9a2ab372aa66e4792886"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-timeline-controls.json",
|
||||
"sha256": "6a86b07770f1cd8d758334fb61c46254197a7f533d24c056fc9a52c317488291"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-timeline.md",
|
||||
"sha256": "612dc3ec4c3d435888055ba20a7f28230ce89ea8b071b8c38d1ea2c147074a96"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-transcript-controls.json",
|
||||
"sha256": "9e4dbdc33806d6fcc912dc3aacc8691a77939e2ce2403032b2a8127c0e407e94"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-transcript.md",
|
||||
"sha256": "9e4ac8c92a3a9eca727c29a77ae428702d19ecdee0cab0e3dfcda0a36bf004db"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui.md",
|
||||
"sha256": "896b9928af85a4c7d588dfca93484980aadb238bd79d8142e671c62f0b191fa8"
|
||||
}
|
||||
],
|
||||
"ownerRestoredToBaseGitBytes": true,
|
||||
"productionLinesChanged": 0
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
# Test audit, Round 7 UI — Experimental settings follow-up
|
||||
|
||||
This separate packet removes **2 registered executions, 2 root renders and 10 net test lines** from `ui/src/pages/InstanceExperimentalSettings.test.tsx`. It adds no helper and changes no production lines. Audit base: `e3effbb9e5c66b838f67fd487987c8bf1007e413`. Prior committed evidence remains byte-identical. Render/execution savings are per complete-suite invocation; no measured runtime or CI-speed claim is made.
|
||||
|
||||
## Exact retirement map
|
||||
|
||||
| Retired registration | Keeper | Observations retained |
|
||||
|---|---|---|
|
||||
| `does not render the Pipelines experimental setting for now` | `does not render the Conference Room Chat experimental setting for now` | expect(headings).not.toContain("Pipelines");; expect(container.querySelector('button[aria-label="Toggle pipelines experimental setting"]')).toBeNull(); |
|
||||
| `shows the cutoff-copy for the worktree run-execution toggle when off` | `renders and patches the worktree run-execution toggle when in a worktree` | expect(container.textContent).toContain( "Only tasks created after enabling will run automatically", );; expect(container.textContent).toContain("Toggling off and on resets the cutoff.");; expect(container.textContent).not.toContain("Running tasks created after");; expect(container.textContent).not.toContain("Execution is suppressed"); |
|
||||
|
||||
InstanceExperimentalSettings.tsx keeps the retired Pipelines/Conference Room settings absent and owns the worktree-run toggle and activation-state banners. Two initial page renders consolidate independently: hidden Pipelines heading/toggle checks join the hidden Conference Room keeper; all off-state cutoff/reset copy and armed/fail-closed banner exclusions join the existing worktree toggle keeper before its click. Runtime worktree metadata, shared settings fixture, renderPage helper and lifecycle match in each pair. Enabled/armed/mismatch/managed/runtime-specific and toggle-interaction cases remain unchanged.
|
||||
|
||||
The AST verifier checks exact setup, shared enclosing hooks and matched cleanup where present, reconstructs candidate text solely from the declared registrations/assertion migrations, and requires exact byte equality plus full-program AST equality outside those edits. No fixture, helper, provider, action order, wait, assertion strength, timer or teardown changes. The IssueChatThread keeper is an existing complete subset proof; InlineEditor’s identical not-null guard is retained once. Every other case stays byte-identical. Default CI includes this file in `@paperclipai/ui` under `general-workspaces-a`, once across the two file shards; workflow/config unchanged.
|
||||
|
||||
## Complete owner-file results
|
||||
|
||||
| Run | Registered | Passed | Failed | Skipped |
|
||||
|---|---:|---:|---:|---:|
|
||||
| Baseline | 55 | 55 | 0 | 0 |
|
||||
| Candidate | 53 | 53 | 0 | 0 |
|
||||
|
||||
From `ui/`: `pnpm exec vitest run src/pages/InstanceExperimentalSettings.test.tsx`.
|
||||
|
||||
All 6 isolated positive controls passed. All 6 deliberate behavior regressions failed at their intended retained/migrated assertion, rather than setup, timeout or a different guard:
|
||||
|
||||
| Regression | Intended guard |
|
||||
|---|---|
|
||||
| pipelines-heading | `expect(headings).not.toContain("Pipelines")` |
|
||||
| pipelines-toggle | `expect(container.querySelector('button[aria-label="Toggle pipelines experimental setting"]')).toBeNull()` |
|
||||
| cutoff-copy | `expect(container.textContent).toContain(` |
|
||||
| reset-copy | `expect(container.textContent).toContain("Toggling off and on resets the cutoff.")` |
|
||||
| armed-banner | `expect(container.textContent).not.toContain("Running tasks created after")` |
|
||||
| fail-closed | `expect(container.textContent).not.toContain("Execution is suppressed")` |
|
||||
|
||||
Exactly one production owner was temporarily changed per control. Every owner was restored byte for byte after each mutation and matched pinned Git bytes. Filtered controls select one keeper; unselected tests do not count as full-suite evidence. [Controls JSON](2026-10-12-test-audit-r7-ui-experimental-controls.json) records exact owner/source hashes, migration/input proof, complete-file run/log digests, mutation bodies, intended assertion failures and restoration receipts. Temporary raw verifiers and logs are identified by digests rather than committed in full.
|
||||
|
||||
The earlier broad `pnpm test:run` was intentionally stopped without completion and is not claimed as passed. Separate packet results are focused proof, not a completed combined delivery-head replay or pending full CI. No push, rebase, PR or merge is included here.
|
||||
@@ -0,0 +1,221 @@
|
||||
{
|
||||
"audit": {
|
||||
"file": "ui/src/components/IssueFiltersPopover.test.tsx",
|
||||
"base": "2e76f5157240ee8b2d42adbdcd4c345aea07c013",
|
||||
"originalSha256": "bc64ad73ccd00e837e92a2ddf0309cf063e30e6a55704b0e8031a6c95d697688",
|
||||
"candidateSha256": "6bdb383ad113f555c1208bbdb1bda2203e027a059751fb9fa7b405d5e9c7f8ef",
|
||||
"allOtherProgramAstUnchanged": true,
|
||||
"allOtherSourceBytesUnchanged": true,
|
||||
"newHelpers": 0,
|
||||
"registeredInvocationsRemoved": 1,
|
||||
"renderInvocationsRemoved": 1,
|
||||
"setupInvocationsRemoved": 1,
|
||||
"netTestLinesRemoved": 22,
|
||||
"migrations": [
|
||||
{
|
||||
"retired": "hides the Priority filter section while priority UI is off (PAP-411)",
|
||||
"keeper": "uses a scrollable popover and a three-column desktop grid",
|
||||
"exactLeadingStatements": 4,
|
||||
"sameEnclosingHooks": true,
|
||||
"explicitCleanupAstEqual": false,
|
||||
"kind": "normal",
|
||||
"exactMigratedStatements": [
|
||||
"expect(popoverContent?.textContent).toContain(\"Status\");",
|
||||
"expect(popoverContent?.textContent).not.toContain(\"Priority\");"
|
||||
],
|
||||
"alreadyExactKeeperStatementsOrBindings": [],
|
||||
"registeredInvocationsRemoved": 1,
|
||||
"renderInvocationsRemoved": 1,
|
||||
"setupInvocationsRemoved": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"verifierSha256": "ff07f5e2e308cfc0f26584a6cd6599bcd98665e79d7f4782ed5bb36b35cb8cb9",
|
||||
"mutationVerifierSha256": "676b973d4838ed130c5ae92d4bc50fb32a65309af8c858450ec34bcce13729e9",
|
||||
"runs": [
|
||||
{
|
||||
"kind": "baseline",
|
||||
"total": 5,
|
||||
"passed": 5,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"jsonSha256": "04cc18d7e6470f2861ac1d76af11bef0e60492f45dd94685df4efe078436bee4",
|
||||
"logSha256": "05761c256ebb185006c0a3fc406347c46ef9543ba1ddcf5242e8f6e8f775356f"
|
||||
},
|
||||
{
|
||||
"kind": "candidate",
|
||||
"total": 4,
|
||||
"passed": 4,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"jsonSha256": "4deabc223e9f57bacf81f0c7d87b621c1eb620f397b54c1b49a876b3603810d0",
|
||||
"logSha256": "d4a57beb3f938c21882056691d74fcb1bfc3db84656987cd3aaa5de8737fdbde"
|
||||
}
|
||||
],
|
||||
"mutations": [
|
||||
{
|
||||
"slug": "status",
|
||||
"owner": "ui/src/components/IssueFiltersPopover.tsx",
|
||||
"sourceSha256": "ea92ceec823ad162f6fd843d094c849b9cd535aba1721059f7ea6d8c780d734b",
|
||||
"title": "uses a scrollable popover and a three-column desktop grid",
|
||||
"mutation": {
|
||||
"before": ">Status</span>",
|
||||
"after": ">Missing status</span>",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(popoverContent?.textContent).toContain(\"Status\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "03e26e0e193e289480f5ee00500ec4d4e0e4d1de112ef708d7754a712fdadacc",
|
||||
"logSha256": "de89d91b9b7e15774cc570b6fed343ace6fe6468c32f62045c4439061400b53e",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "81b7e1eb1de267f667c001ed838b65523fa8015f4265c84d82c19b9dd847d172",
|
||||
"logSha256": "8f981560c571bacd648edcc6322ceee073cad7039085186a8381aa62f447b2be",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected 'FiltersQuick filtersAllActiveBacklogD\u2026' to contain 'Status'\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/IssueFiltersPopover.test.tsx:76:41\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:1628:35\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:26\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3321:20\n at new Promise (<anonymous>)\n at runWithCancel (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3316:10)\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3301:20\n at new Promise (<anonymous>)\n at runWithTimeout (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3259:10)\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3882:64"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "priority",
|
||||
"owner": "ui/src/components/IssueFiltersPopover.tsx",
|
||||
"sourceSha256": "ea92ceec823ad162f6fd843d094c849b9cd535aba1721059f7ea6d8c780d734b",
|
||||
"title": "uses a scrollable popover and a three-column desktop grid",
|
||||
"mutation": {
|
||||
"before": "{SHOW_TASK_PRIORITY_UI && (",
|
||||
"after": "{true && (",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(popoverContent?.textContent).not.toContain(\"Priority\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "2b9d14ef5dba8d78ca254915e80969abb778dce7b6648548cc9684b3c79b698c",
|
||||
"logSha256": "381ff350cd72e952c86246a8dd06867cd766e776fd6f471b71e220b312799866",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "d816a0329a953d6dd71e16eca02e95439534e24e753d50f1ea742ad43d9e9396",
|
||||
"logSha256": "3fc77abdcbcedc235471237fdbb6a7d36caf9aa765193a9c62ffee4d39b99bb3",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected 'FiltersQuick filtersAllActiveBacklogD\u2026' not to contain 'Priority'\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/IssueFiltersPopover.test.tsx:77:45\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:1628:35\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:26\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3321:20\n at new Promise (<anonymous>)\n at runWithCancel (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3316:10)\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3301:20\n at new Promise (<anonymous>)\n at runWithTimeout (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3259:10)\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3882:64"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"priorEvidenceUnchanged": [
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-agentconfig-controls.json",
|
||||
"sha256": "cfb4357610beaa464cdb26848f74a7b8d967d6409c63dbd6821c92886a9cf980"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-agentconfig.md",
|
||||
"sha256": "ea6d5dfc8cedcd653edd55ca9d77568431413a351f4de5db77ca6ac8f22b051a"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appboundary-controls.json",
|
||||
"sha256": "bad49e7bc92dea919df6b980bfa45e7452984cf31a6fd4655b355ba0444ff9a6"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appboundary.md",
|
||||
"sha256": "cd6f173584db0d485004af6f85b1ce78fa65b19d8c6ef582b061f0d232c6c1ed"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appdetail-controls.json",
|
||||
"sha256": "7906fde0d62e14a7511b5cf45f864c9386a4c377922333eefc7f7e703c832f6a"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appdetail.md",
|
||||
"sha256": "715f23cd27502c92d0f5d1b83b91bcac03f254c73ab63b44181ae76939805229"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-attachments-controls.json",
|
||||
"sha256": "c4ff66a3226e1edafd286cad0ca45c9445795b46944cf70d606c59a754913f3a"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-attachments.md",
|
||||
"sha256": "d38715393c95306d10e871a5a2c9a32f105fa1452871cd7ad030d86dbbdb7416"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-controls.json",
|
||||
"sha256": "0d445f6f066032f2d9cd724525a8d7d2290246cbfeee1f6ab4b44818467af2a7"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-experimental-controls.json",
|
||||
"sha256": "9c72abee7ee1a937fdbd6ccee870320308bc7ce06b4fc1e338cd9bd3b0efba6b"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-experimental.md",
|
||||
"sha256": "93b7583a8ebba39dc97e390918fd62029955a00beda22756f55bd6374acc3737"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-inline-controls.json",
|
||||
"sha256": "af9d3f115e6e0518c2c0a2e11b8913e7aa82a35c848f114e6750884323601e17"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-inline.md",
|
||||
"sha256": "52d8e27970bd1c091ae7edf403b2331e921081da9198270df65ff779a8efc1bc"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-issuechat-controls.json",
|
||||
"sha256": "45d86fa901c8ab40bc3fe98d266e3ba1a7bbc93edb7bc2aae60ccd9bfa130c37"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-issuechat.md",
|
||||
"sha256": "15e84a553c5a468aea013941f68d3aa517bfb5a13ae296a90e1a39586f85de8e"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-issuedetail-controls.json",
|
||||
"sha256": "a56f183f1c6b940662db0c4bfb62457eda0cec453c2019b439ec716ed9d2a3e1"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-issuedetail.md",
|
||||
"sha256": "e137af5b991c936a167d6ad6f3c710b99688e939f839b163b203259fc998ded8"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-route-controls.json",
|
||||
"sha256": "0a72a7770ec749f2c0507a74d395e65d70b722d0b9d2a767a2c066a67ed46382"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-route.md",
|
||||
"sha256": "9b5e1543163d6c9d0958aa3e377a593ec458f6674ce1ddb2bf3ca158786f09c4"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-sidebar-controls.json",
|
||||
"sha256": "ae9f24746e67432cf6247c5da130b9c1bba46fc85112c0610d3f18545dfce326"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-sidebar.md",
|
||||
"sha256": "5e267441c43aa8375fa5c54edcbd2879428d657708be9a2ab372aa66e4792886"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-timeline-controls.json",
|
||||
"sha256": "6a86b07770f1cd8d758334fb61c46254197a7f533d24c056fc9a52c317488291"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-timeline.md",
|
||||
"sha256": "612dc3ec4c3d435888055ba20a7f28230ce89ea8b071b8c38d1ea2c147074a96"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-transcript-controls.json",
|
||||
"sha256": "9e4dbdc33806d6fcc912dc3aacc8691a77939e2ce2403032b2a8127c0e407e94"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-transcript.md",
|
||||
"sha256": "9e4ac8c92a3a9eca727c29a77ae428702d19ecdee0cab0e3dfcda0a36bf004db"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui.md",
|
||||
"sha256": "896b9928af85a4c7d588dfca93484980aadb238bd79d8142e671c62f0b191fa8"
|
||||
}
|
||||
],
|
||||
"ownerRestoredToBaseGitBytes": true,
|
||||
"productionLinesChanged": 0
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
# Test audit, Round 7 UI — Issue filter popover follow-up
|
||||
|
||||
This separate packet removes **1 registered executions, 1 rendered scenarios and 22 net test lines** from `ui/src/components/IssueFiltersPopover.test.tsx`. It adds no helper and changes no production lines. Audit base: `2e76f5157240ee8b2d42adbdcd4c345aea07c013`. All prior committed proof remains byte-identical. Registration/render savings are per complete-suite invocation; no measured runtime or CI-speed claim is made. A service-worker retirement counts only initializer setup, never a render.
|
||||
|
||||
## Exact retirement map
|
||||
|
||||
| Retired registration | Keeper | Exact observations migrated |
|
||||
|---|---|---|
|
||||
| `hides the Priority filter section while priority UI is off (PAP-411)` | `uses a scrollable popover and a three-column desktop grid` | expect(popoverContent?.textContent).toContain("Status");; expect(popoverContent?.textContent).not.toContain("Priority"); |
|
||||
|
||||
Both registered cases use identical streamlined props, filter state, agents/projects/labels and routine-visibility flag, root/act render and positive popover lookup. The existing rich scroll/layout keeper gains exact Status-presence and Priority-absence checks before its original layout assertions. Real IssueFiltersPopover.tsx gates the Priority section independently of Status. Option search, legacy presentation and interactive inbox-scope cases remain unchanged. Existing teardown is unchanged.
|
||||
|
||||
The verifier requires matching setup statements, enclosing hooks and explicit teardown where present. It reconstructs candidate source solely from the declared registrations/assertion migrations and requires exact byte equality plus full-program AST equality outside those edits. Existing shared variable bindings, mock arguments and provider/component inputs remain the same. No other fixture, helper, action order, wait, assertion strength, timer or cleanup changes. Default CI includes the file in `@paperclipai/ui` under `general-workspaces-a`, once across its two file shards, with no workflow/config change.
|
||||
|
||||
## Complete owner-file results
|
||||
|
||||
| Run | Registered | Passed | Failed | Skipped |
|
||||
|---|---:|---:|---:|---:|
|
||||
| Baseline | 5 | 5 | 0 | 0 |
|
||||
| Candidate | 4 | 4 | 0 | 0 |
|
||||
|
||||
From `ui/`: `pnpm exec vitest run src/components/IssueFiltersPopover.test.tsx`.
|
||||
|
||||
All 2 separately selected positive controls passed. All 2 distinct production-owner regressions failed at intended retained/migrated assertions, not setup, timeout or another guard:
|
||||
|
||||
| Regression | Intended guard |
|
||||
|---|---|
|
||||
| status | `expect(popoverContent?.textContent).toContain("Status")` |
|
||||
| priority | `expect(popoverContent?.textContent).not.toContain("Priority")` |
|
||||
|
||||
Exactly one production owner changed per control, and every owner was restored byte for byte after each mutation and checked against pinned Git bytes. Literal keeper-name filters are escaped; unselected cases are not full-suite evidence. The initial first-install receipt verifier mistook emit( for it( and rejected its receipt despite the intended test failure. The declaration-boundary matcher was corrected and that control rerun; the rejected verifier attempt supplies no accepted evidence.
|
||||
|
||||
[Controls JSON](2026-10-12-test-audit-r7-ui-filters-controls.json) preserves source/owner hashes, exact before/after migrations, matched setup and variable-binding proof, complete-file run/log digests, intended assertion failures and restoration checks. Temporary raw scripts/logs are identified by digests rather than committed in full.
|
||||
|
||||
The earlier broad local `pnpm test:run` was intentionally stopped before completion and is not claimed as passed. These separate focused packets precede delivery-head replay and full CI. This packet includes no push, rebase, PR or merge.
|
||||
@@ -0,0 +1,180 @@
|
||||
{
|
||||
"audit": {
|
||||
"file": "ui/src/components/InlineEditor.test.tsx",
|
||||
"base": "e3effbb9e5c66b838f67fd487987c8bf1007e413",
|
||||
"originalSha256": "50117c71ad5cf0319742d5aff24d3b36b03576d45f7d7eb5759574cf373afbe6",
|
||||
"candidateSha256": "d556cf16f5ca87e44174b4e680a66ce19b69eb3fc01834544795638b7e898f32",
|
||||
"allOtherProgramAstUnchanged": true,
|
||||
"allOtherSourceBytesUnchanged": true,
|
||||
"newHelpers": 0,
|
||||
"registeredInvocationsRemoved": 1,
|
||||
"rootRendersRemoved": 1,
|
||||
"netTestLinesRemoved": 15,
|
||||
"migrations": [
|
||||
{
|
||||
"retired": "marks multiline preview textboxes as multiline",
|
||||
"keeper": "enters multiline edit mode from the keyboard preview surface",
|
||||
"exactSetupStatements": 4,
|
||||
"sameEnclosingHooks": true,
|
||||
"exactCleanupStatements": 1,
|
||||
"migratedGuards": [
|
||||
"expect(preview?.getAttribute(\"aria-multiline\")).toBe(\"true\");",
|
||||
"expect(preview?.tabIndex).toBe(0);"
|
||||
],
|
||||
"exactDuplicateGuardAlreadyKept": [
|
||||
"expect(preview).not.toBeNull();"
|
||||
],
|
||||
"registeredInvocationsRemoved": 1,
|
||||
"rootRendersRemoved": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"verifierSha256": "084bdbc359e510397ef64daeb24e259efbc62c8b5d2c56d3e09d7f2534f155aa",
|
||||
"mutationVerifierSha256": "ca8463047109d38a447d93fb94a19bb8efe9b1df440e0abf91ab31a8c0a358a2",
|
||||
"runs": [
|
||||
{
|
||||
"kind": "baseline",
|
||||
"total": 10,
|
||||
"passed": 10,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"jsonSha256": "e2d0e45ee5a399f94e9dae9063e10eb82c4732e8735abb2910e7a99ce43b9e56",
|
||||
"logSha256": "ff89195de1b2aea03e77b06103dc733d634075241a30cddf8fcf83cf0523cb38"
|
||||
},
|
||||
{
|
||||
"kind": "candidate",
|
||||
"total": 9,
|
||||
"passed": 9,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"jsonSha256": "9e64a19f6fe426eaa9976f6e57c1b3df624a90bc6985ed1b68ce2dedd7d8b138",
|
||||
"logSha256": "6001db7d0b44f5162dfb7f3277f7a41ae44c32d8c07c70055c0c69a0fca470a9"
|
||||
}
|
||||
],
|
||||
"mutations": [
|
||||
{
|
||||
"slug": "multiline",
|
||||
"owner": "ui/src/components/InlineEditor.tsx",
|
||||
"sourceSha256": "9b14c37ef76ab2f6372fd56e9b5b7d3125f50cb352dfec8c4a320cf91d77ef3c",
|
||||
"title": "enters multiline edit mode from the keyboard preview surface",
|
||||
"mutation": {
|
||||
"before": "aria-multiline=\"true\"",
|
||||
"after": "aria-multiline=\"false\"",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(preview?.getAttribute(\"aria-multiline\")).toBe(\"true\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "61dc2a3025f09b64b8598cd30c3417fb352519278c7c62b794dff2f236849c9d",
|
||||
"logSha256": "4b25b8b35d984b55fa024c6c36b2ec739ba1cac2383f325edba1787ec5b7b764",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "4341b22562ba43c8ab24ce4e90eb83cf99c143a89aa87785c0acb6b3935e1290",
|
||||
"logSha256": "42c7242f5b1887c6eee56ad0a6be72a429432bc514cdc8f6a6725ced42caad80",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected 'false' to be 'true' // Object.is equality\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/InlineEditor.test.tsx:221:53\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:1628:35\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:26\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3321:20\n at new Promise (<anonymous>)\n at runWithCancel (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3316:10)\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3301:20\n at new Promise (<anonymous>)\n at runWithTimeout (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3259:10)\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3882:64"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "tab-index",
|
||||
"owner": "ui/src/components/InlineEditor.tsx",
|
||||
"sourceSha256": "9b14c37ef76ab2f6372fd56e9b5b7d3125f50cb352dfec8c4a320cf91d77ef3c",
|
||||
"title": "enters multiline edit mode from the keyboard preview surface",
|
||||
"mutation": {
|
||||
"before": "tabIndex={0}",
|
||||
"after": "tabIndex={-1}",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(preview?.tabIndex).toBe(0)",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "b6064902d779a1e4e32ed95b27fcae92c6a23f52818983552ff628bf3bb57d04",
|
||||
"logSha256": "09f4dbfc349e5dfafac95f9a3be763025bd88b509d4c3e4cdb7b9aec091f21d2",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "a97cb51553559f3ab8e7ccc074a9c71fc29b06acd0c3d098861c57432fda2452",
|
||||
"logSha256": "561db47d821ce123ed915b2f6428cdc2990d4ea4bfebefb78c8875f822ce8617",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected -1 to be +0 // Object.is equality\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/InlineEditor.test.tsx:222:31\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:1628:35\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:26\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3321:20\n at new Promise (<anonymous>)\n at runWithCancel (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3316:10)\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3301:20\n at new Promise (<anonymous>)\n at runWithTimeout (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3259:10)\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3882:64"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"priorEvidenceUnchanged": [
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appboundary-controls.json",
|
||||
"sha256": "bad49e7bc92dea919df6b980bfa45e7452984cf31a6fd4655b355ba0444ff9a6"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appboundary.md",
|
||||
"sha256": "cd6f173584db0d485004af6f85b1ce78fa65b19d8c6ef582b061f0d232c6c1ed"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appdetail-controls.json",
|
||||
"sha256": "7906fde0d62e14a7511b5cf45f864c9386a4c377922333eefc7f7e703c832f6a"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appdetail.md",
|
||||
"sha256": "715f23cd27502c92d0f5d1b83b91bcac03f254c73ab63b44181ae76939805229"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-attachments-controls.json",
|
||||
"sha256": "c4ff66a3226e1edafd286cad0ca45c9445795b46944cf70d606c59a754913f3a"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-attachments.md",
|
||||
"sha256": "d38715393c95306d10e871a5a2c9a32f105fa1452871cd7ad030d86dbbdb7416"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-controls.json",
|
||||
"sha256": "0d445f6f066032f2d9cd724525a8d7d2290246cbfeee1f6ab4b44818467af2a7"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-route-controls.json",
|
||||
"sha256": "0a72a7770ec749f2c0507a74d395e65d70b722d0b9d2a767a2c066a67ed46382"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-route.md",
|
||||
"sha256": "9b5e1543163d6c9d0958aa3e377a593ec458f6674ce1ddb2bf3ca158786f09c4"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-sidebar-controls.json",
|
||||
"sha256": "ae9f24746e67432cf6247c5da130b9c1bba46fc85112c0610d3f18545dfce326"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-sidebar.md",
|
||||
"sha256": "5e267441c43aa8375fa5c54edcbd2879428d657708be9a2ab372aa66e4792886"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-timeline-controls.json",
|
||||
"sha256": "6a86b07770f1cd8d758334fb61c46254197a7f533d24c056fc9a52c317488291"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-timeline.md",
|
||||
"sha256": "612dc3ec4c3d435888055ba20a7f28230ce89ea8b071b8c38d1ea2c147074a96"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-transcript-controls.json",
|
||||
"sha256": "9e4dbdc33806d6fcc912dc3aacc8691a77939e2ce2403032b2a8127c0e407e94"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-transcript.md",
|
||||
"sha256": "9e4ac8c92a3a9eca727c29a77ae428702d19ecdee0cab0e3dfcda0a36bf004db"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui.md",
|
||||
"sha256": "896b9928af85a4c7d588dfca93484980aadb238bd79d8142e671c62f0b191fa8"
|
||||
}
|
||||
],
|
||||
"ownerRestoredToBaseGitBytes": true,
|
||||
"productionLinesChanged": 0
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
# Test audit, Round 7 UI — Inline editor accessibility follow-up
|
||||
|
||||
This separate packet removes **1 registered executions, 1 root renders and 15 net test lines** from `ui/src/components/InlineEditor.test.tsx`. It adds no helper and changes no production lines. Audit base: `e3effbb9e5c66b838f67fd487987c8bf1007e413`. Prior committed evidence remains byte-identical. Render/execution savings are per complete-suite invocation; no measured runtime or CI-speed claim is made.
|
||||
|
||||
## Exact retirement map
|
||||
|
||||
| Retired registration | Keeper | Observations retained |
|
||||
|---|---|---|
|
||||
| `marks multiline preview textboxes as multiline` | `enters multiline edit mode from the keyboard preview surface` | expect(preview?.getAttribute("aria-multiline")).toBe("true");; expect(preview?.tabIndex).toBe(0); |
|
||||
|
||||
InlineEditor.tsx exposes a focusable multiline preview textbox and enters edit mode on Enter. Both tests use identical non-empty value, multiline prop, fresh resolved onSave mock, real root, act render, preview query and unmount. The keyboard keeper already has the same not-null assertion; that exact duplicate is retained once. Exact aria-multiline and tabIndex guards move before Enter, preserving keyboard editing and preview/editor assertions. Focus, nullable save, click-entry, prop-sync and blur behavior remain distinct and unchanged.
|
||||
|
||||
The AST verifier checks exact setup, shared enclosing hooks and matched cleanup where present, reconstructs candidate text solely from the declared registrations/assertion migrations, and requires exact byte equality plus full-program AST equality outside those edits. No fixture, helper, provider, action order, wait, assertion strength, timer or teardown changes. The IssueChatThread keeper is an existing complete subset proof; InlineEditor’s identical not-null guard is retained once. Every other case stays byte-identical. Default CI includes this file in `@paperclipai/ui` under `general-workspaces-a`, once across the two file shards; workflow/config unchanged.
|
||||
|
||||
## Complete owner-file results
|
||||
|
||||
| Run | Registered | Passed | Failed | Skipped |
|
||||
|---|---:|---:|---:|---:|
|
||||
| Baseline | 10 | 10 | 0 | 0 |
|
||||
| Candidate | 9 | 9 | 0 | 0 |
|
||||
|
||||
From `ui/`: `pnpm exec vitest run src/components/InlineEditor.test.tsx`.
|
||||
|
||||
All 2 isolated positive controls passed. All 2 deliberate behavior regressions failed at their intended retained/migrated assertion, rather than setup, timeout or a different guard:
|
||||
|
||||
| Regression | Intended guard |
|
||||
|---|---|
|
||||
| multiline | `expect(preview?.getAttribute("aria-multiline")).toBe("true")` |
|
||||
| tab-index | `expect(preview?.tabIndex).toBe(0)` |
|
||||
|
||||
Exactly one production owner was temporarily changed per control. Every owner was restored byte for byte after each mutation and matched pinned Git bytes. Filtered controls select one keeper; unselected tests do not count as full-suite evidence. [Controls JSON](2026-10-12-test-audit-r7-ui-inline-controls.json) records exact owner/source hashes, migration/input proof, complete-file run/log digests, mutation bodies, intended assertion failures and restoration receipts. Temporary raw verifiers and logs are identified by digests rather than committed in full.
|
||||
|
||||
The earlier broad `pnpm test:run` was intentionally stopped without completion and is not claimed as passed. Separate packet results are focused proof, not a completed combined delivery-head replay or pending full CI. No push, rebase, PR or merge is included here.
|
||||
@@ -0,0 +1,145 @@
|
||||
{
|
||||
"audit": {
|
||||
"file": "ui/src/components/IssueChatThread.test.tsx",
|
||||
"base": "e3effbb9e5c66b838f67fd487987c8bf1007e413",
|
||||
"originalSha256": "226728e901d702ff59651f4b0d1a6fa33b34654a8410c58f2f42cebf7022113e",
|
||||
"candidateSha256": "4c8db9834c9bd6bd3ca77420d6dc5ec872903d35f6168dc177a5247372867593",
|
||||
"retired": "does not auto-scroll to the latest comment on initial load",
|
||||
"keeper": "can keep the page at the top on initial load while preserving manual jump-to-latest",
|
||||
"sameEnclosingHooks": true,
|
||||
"exactSubsetPrefixStatements": 20,
|
||||
"exactSubsetCleanupStatements": 4,
|
||||
"keeperBytesUnchanged": true,
|
||||
"allOtherSourceBytesUnchanged": true,
|
||||
"allOtherProgramAstUnchanged": true,
|
||||
"registeredInvocationsRemoved": 1,
|
||||
"rootRendersRemoved": 1,
|
||||
"netTestLinesRemoved": 50,
|
||||
"newHelpers": 0,
|
||||
"retainedExactInitialGuards": [
|
||||
"expect(elementScrollToMock).not.toHaveBeenCalled();",
|
||||
"expect(scrollIntoViewMock).not.toHaveBeenCalled();"
|
||||
]
|
||||
},
|
||||
"verifierSha256": "d5589d82c62e06412eae150b239b5552526428b764362485070ac3846a95789a",
|
||||
"mutationVerifierSha256": "97072371ef809b8bdefbf09dcacd261989132a4135d67fcf857152dd179d2f03",
|
||||
"runs": [
|
||||
{
|
||||
"kind": "baseline",
|
||||
"total": 100,
|
||||
"passed": 100,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"jsonSha256": "efc81cf6ef5ca2bc0f495d185bb10ea905dcb003b084fc20ea29d76f122ed7e2",
|
||||
"logSha256": "4d1be86a78cc5a8868d9fc99e53b4ddaa1d94deac818cea48952b887ca3cbca0"
|
||||
},
|
||||
{
|
||||
"kind": "candidate",
|
||||
"total": 99,
|
||||
"passed": 99,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"jsonSha256": "82badc1cc88a0e72db6dace6d9bae69d239d53eb9a187c9b286a6a6c4bfb75e5",
|
||||
"logSha256": "0eb343b1ddd666c246c4df358a8b9210cfe97f9ecef7e8abe756103b4e16a7a3"
|
||||
}
|
||||
],
|
||||
"mutations": [
|
||||
{
|
||||
"slug": "initial-auto-scroll",
|
||||
"owner": "ui/src/components/IssueChatThread.tsx",
|
||||
"sourceSha256": "23624e4e25b60c9ce8cc91fa548bfd46e18666723e5aa8d9f882846ded3bdf82",
|
||||
"title": "can keep the page at the top on initial load while preserving manual jump-to-latest",
|
||||
"mutation": {
|
||||
"before": " if (!autoScrollToLatestOnInitialLoad) return;",
|
||||
"after": " // Regression: ignore caller initial-scroll opt-out.",
|
||||
"replacementCount": 1,
|
||||
"additionalPreClosingTagReplacement": false
|
||||
},
|
||||
"intendedGuard": ".not.toHaveBeenCalled();",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "018d96099478a6400770da42da7a7af754e12a05c0ad3981b270fcd0d9317a7f",
|
||||
"logSha256": "34e23348df52acad5ab2e1c6374125ae9f746f21dd3ea6bc5d4155fceb71590d",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "5a6c5faccd5b873cf5ddf2ef18b14f12fc2b3d596c15c11ca606d84a76ecd1d6",
|
||||
"logSha256": "c87b37dcd855277f778930cf10f4ee89dd4c19627cebfd5d6452378c9ee44530",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected \"vi.fn()\" to not be called at all, but actually been called 6 times\n\nReceived:\n\n 1st vi.fn() call:\n\n Array [\n Object {\n \"behavior\": \"smooth\",\n \"top\": 114916,\n },\n ]\n\n 2nd vi.fn() call:\n\n Array [\n Object {\n \"behavior\": \"auto\",\n \"top\": 114916,\n },\n ]\n\n 3rd vi.fn() call:\n\n Array [\n Object {\n \"behavior\": \"auto\",\n \"top\": 114916,\n },\n ]\n\n 4th vi.fn() call:\n\n Array [\n Object {\n \"behavior\": \"auto\",\n \"top\": 114916,\n },\n ]\n\n 5th vi.fn() call:\n\n Array [\n Object {\n \"behavior\": \"auto\",\n \"top\": 114916,\n },\n ]\n\n 6th vi.fn() call:\n\n Array [\n Object {\n \"behavior\": \"auto\",\n \"top\": 114916,\n },\n ]\n\n\nNumber of calls: 6\n\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:2214:51)\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:1944:14)\n at Proxy.methodWrapper (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/chai@6.3.0/node_modules/chai/index.js:1737:25)\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/IssueChatThread.test.tsx:1217:37\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:1628:35\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:26\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3321:20\n at new Promise (<anonymous>)\n at runWithCancel (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3316:10)\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3301:20"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"priorEvidenceUnchanged": [
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appboundary-controls.json",
|
||||
"sha256": "bad49e7bc92dea919df6b980bfa45e7452984cf31a6fd4655b355ba0444ff9a6"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appboundary.md",
|
||||
"sha256": "cd6f173584db0d485004af6f85b1ce78fa65b19d8c6ef582b061f0d232c6c1ed"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appdetail-controls.json",
|
||||
"sha256": "7906fde0d62e14a7511b5cf45f864c9386a4c377922333eefc7f7e703c832f6a"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appdetail.md",
|
||||
"sha256": "715f23cd27502c92d0f5d1b83b91bcac03f254c73ab63b44181ae76939805229"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-attachments-controls.json",
|
||||
"sha256": "c4ff66a3226e1edafd286cad0ca45c9445795b46944cf70d606c59a754913f3a"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-attachments.md",
|
||||
"sha256": "d38715393c95306d10e871a5a2c9a32f105fa1452871cd7ad030d86dbbdb7416"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-controls.json",
|
||||
"sha256": "0d445f6f066032f2d9cd724525a8d7d2290246cbfeee1f6ab4b44818467af2a7"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-route-controls.json",
|
||||
"sha256": "0a72a7770ec749f2c0507a74d395e65d70b722d0b9d2a767a2c066a67ed46382"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-route.md",
|
||||
"sha256": "9b5e1543163d6c9d0958aa3e377a593ec458f6674ce1ddb2bf3ca158786f09c4"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-sidebar-controls.json",
|
||||
"sha256": "ae9f24746e67432cf6247c5da130b9c1bba46fc85112c0610d3f18545dfce326"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-sidebar.md",
|
||||
"sha256": "5e267441c43aa8375fa5c54edcbd2879428d657708be9a2ab372aa66e4792886"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-timeline-controls.json",
|
||||
"sha256": "6a86b07770f1cd8d758334fb61c46254197a7f533d24c056fc9a52c317488291"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-timeline.md",
|
||||
"sha256": "612dc3ec4c3d435888055ba20a7f28230ce89ea8b071b8c38d1ea2c147074a96"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-transcript-controls.json",
|
||||
"sha256": "9e4dbdc33806d6fcc912dc3aacc8691a77939e2ce2403032b2a8127c0e407e94"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-transcript.md",
|
||||
"sha256": "9e4ac8c92a3a9eca727c29a77ae428702d19ecdee0cab0e3dfcda0a36bf004db"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui.md",
|
||||
"sha256": "896b9928af85a4c7d588dfca93484980aadb238bd79d8142e671c62f0b191fa8"
|
||||
}
|
||||
],
|
||||
"ownerRestoredToBaseGitBytes": true,
|
||||
"productionLinesChanged": 0
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
# Test audit, Round 7 UI — Issue thread initial scroll follow-up
|
||||
|
||||
This separate packet removes **1 registered executions, 1 root renders and 50 net test lines** from `ui/src/components/IssueChatThread.test.tsx`. It adds no helper and changes no production lines. Audit base: `e3effbb9e5c66b838f67fd487987c8bf1007e413`. Prior committed evidence remains byte-identical. Render/execution savings are per complete-suite invocation; no measured runtime or CI-speed claim is made.
|
||||
|
||||
## Exact retirement map
|
||||
|
||||
| Retired registration | Keeper | Observations retained |
|
||||
|---|---|---|
|
||||
| `does not auto-scroll to the latest comment on initial load` | `can keep the page at the top on initial load while preserving manual jump-to-latest` | expect(elementScrollToMock).not.toHaveBeenCalled();; expect(scrollIntoViewMock).not.toHaveBeenCalled(); |
|
||||
|
||||
IssueChatThread.tsx keeps default initial viewport stable through the autoScrollToLatestOnInitialLoad opt-out, while an explicit Jump to latest action owns manual scrolling. The retired complete initial test is an exact AST subset of the keeper: all twenty setup/initial-judgment statements and all four cleanup statements match. Both use the exact same long-thread comments/runs/events/maps, fake timers, real scroll host, scrollTo mock, scrollIntoView prototype override and 500 ms timer advance. The keeper remains byte-identical, including both no-scroll guards before clicking. Hash routing, explicit auto-scroll and user-interruption cases remain byte-identical.
|
||||
|
||||
The AST verifier checks exact setup, shared enclosing hooks and matched cleanup where present, reconstructs candidate text solely from the declared registrations/assertion migrations, and requires exact byte equality plus full-program AST equality outside those edits. No fixture, helper, provider, action order, wait, assertion strength, timer or teardown changes. The IssueChatThread keeper is an existing complete subset proof; InlineEditor’s identical not-null guard is retained once. Every other case stays byte-identical. Default CI includes this file in `@paperclipai/ui` under `general-workspaces-a`, once across the two file shards; workflow/config unchanged.
|
||||
|
||||
## Complete owner-file results
|
||||
|
||||
| Run | Registered | Passed | Failed | Skipped |
|
||||
|---|---:|---:|---:|---:|
|
||||
| Baseline | 100 | 100 | 0 | 0 |
|
||||
| Candidate | 99 | 99 | 0 | 0 |
|
||||
|
||||
From `ui/`: `pnpm exec vitest run src/components/IssueChatThread.test.tsx`.
|
||||
|
||||
All 1 isolated positive controls passed. All 1 deliberate behavior regressions failed at their intended retained/migrated assertion, rather than setup, timeout or a different guard:
|
||||
|
||||
| Regression | Intended guard |
|
||||
|---|---|
|
||||
| initial-auto-scroll | `.not.toHaveBeenCalled();` |
|
||||
|
||||
Exactly one production owner was temporarily changed per control. Every owner was restored byte for byte after each mutation and matched pinned Git bytes. Filtered controls select one keeper; unselected tests do not count as full-suite evidence. [Controls JSON](2026-10-12-test-audit-r7-ui-issuechat-controls.json) records exact owner/source hashes, migration/input proof, complete-file run/log digests, mutation bodies, intended assertion failures and restoration receipts. Temporary raw verifiers and logs are identified by digests rather than committed in full.
|
||||
|
||||
The earlier broad `pnpm test:run` was intentionally stopped without completion and is not claimed as passed. Separate packet results are focused proof, not a completed combined delivery-head replay or pending full CI. No push, rebase, PR or merge is included here.
|
||||
@@ -0,0 +1,149 @@
|
||||
{
|
||||
"audit": {
|
||||
"file": "ui/src/pages/IssueDetail.test.tsx",
|
||||
"base": "e3effbb9e5c66b838f67fd487987c8bf1007e413",
|
||||
"originalSha256": "3f70d91da4a6b272ee190b33fd17c3e09e04df3dd42d6ab4f2c9cb74e2bca0c4",
|
||||
"candidateSha256": "06b026c4bd296848011d1cc30f89711453a9db0c1e4c743fa22ae653b3e942d7",
|
||||
"allOtherProgramAstUnchanged": true,
|
||||
"allOtherSourceBytesUnchanged": true,
|
||||
"newHelpers": 0,
|
||||
"registeredInvocationsRemoved": 1,
|
||||
"rootRendersRemoved": 1,
|
||||
"netTestLinesRemoved": 11,
|
||||
"migrations": [
|
||||
{
|
||||
"retired": "hides file viewer entry points by default",
|
||||
"keeper": "hides the plan decomposition panel by default",
|
||||
"exactSetupStatements": 4,
|
||||
"sameEnclosingHooks": true,
|
||||
"exactCleanupStatements": 0,
|
||||
"migratedGuards": [
|
||||
"expect(\n container.querySelector('[aria-label=\"Open file in this issue\"]'),\n ).toBeNull();"
|
||||
],
|
||||
"exactDuplicateGuardAlreadyKept": [],
|
||||
"registeredInvocationsRemoved": 1,
|
||||
"rootRendersRemoved": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"verifierSha256": "084bdbc359e510397ef64daeb24e259efbc62c8b5d2c56d3e09d7f2534f155aa",
|
||||
"mutationVerifierSha256": "ca8463047109d38a447d93fb94a19bb8efe9b1df440e0abf91ab31a8c0a358a2",
|
||||
"runs": [
|
||||
{
|
||||
"kind": "baseline",
|
||||
"total": 141,
|
||||
"passed": 141,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"jsonSha256": "efc0588840631e46a0468684533c2a0df23ce43e24e9f165b69797ed4ba4f8f2",
|
||||
"logSha256": "c2d0323c3d9b9050231dcdd9ff68c0bf2796911ae563283d37d253b990973b87"
|
||||
},
|
||||
{
|
||||
"kind": "candidate",
|
||||
"total": 140,
|
||||
"passed": 140,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"jsonSha256": "5710da0c420896d10b0e02a42310067ef3f56ae171831ea74c02943f4d38c9e4",
|
||||
"logSha256": "45b5a51b85ec8358643fd4b6bfe0851d77d1f97f6adf7c59fdec0dbed36d569f"
|
||||
}
|
||||
],
|
||||
"mutations": [
|
||||
{
|
||||
"slug": "file-viewer",
|
||||
"owner": "ui/src/pages/IssueDetail.tsx",
|
||||
"sourceSha256": "17b28ad871c2f00fa2d1153d50f151ebd0bed68c85d5a0f2a50164a2f1a612b2",
|
||||
"title": "hides the plan decomposition panel by default",
|
||||
"mutation": {
|
||||
"before": "instanceExperimentalSettings?.enableExperimentalFileViewer === true;",
|
||||
"after": "true;",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "container.querySelector('[aria-label=\"Open file in this issue\"]')",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "cfcf22e69da57c125f9622c1c692fbadf48181cf05804986c7f7d967f38295a0",
|
||||
"logSha256": "e8175ef85629eb1163704e686efcbb7c0e08ea9e0de852541945a0448d79223f",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "b0e830d03ce630f19deae86869b4fa642ac41047da6d59fe4e363633d486e424",
|
||||
"logSha256": "b7a6464f68a800d0218d044694c0f8405e993f18ee831634a9c22b4b00204c86",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected <button \u2026(3)>\u2026(1)</button> to be null\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/pages/IssueDetail.test.tsx:4195:7\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"priorEvidenceUnchanged": [
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appboundary-controls.json",
|
||||
"sha256": "bad49e7bc92dea919df6b980bfa45e7452984cf31a6fd4655b355ba0444ff9a6"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appboundary.md",
|
||||
"sha256": "cd6f173584db0d485004af6f85b1ce78fa65b19d8c6ef582b061f0d232c6c1ed"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appdetail-controls.json",
|
||||
"sha256": "7906fde0d62e14a7511b5cf45f864c9386a4c377922333eefc7f7e703c832f6a"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appdetail.md",
|
||||
"sha256": "715f23cd27502c92d0f5d1b83b91bcac03f254c73ab63b44181ae76939805229"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-attachments-controls.json",
|
||||
"sha256": "c4ff66a3226e1edafd286cad0ca45c9445795b46944cf70d606c59a754913f3a"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-attachments.md",
|
||||
"sha256": "d38715393c95306d10e871a5a2c9a32f105fa1452871cd7ad030d86dbbdb7416"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-controls.json",
|
||||
"sha256": "0d445f6f066032f2d9cd724525a8d7d2290246cbfeee1f6ab4b44818467af2a7"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-route-controls.json",
|
||||
"sha256": "0a72a7770ec749f2c0507a74d395e65d70b722d0b9d2a767a2c066a67ed46382"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-route.md",
|
||||
"sha256": "9b5e1543163d6c9d0958aa3e377a593ec458f6674ce1ddb2bf3ca158786f09c4"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-sidebar-controls.json",
|
||||
"sha256": "ae9f24746e67432cf6247c5da130b9c1bba46fc85112c0610d3f18545dfce326"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-sidebar.md",
|
||||
"sha256": "5e267441c43aa8375fa5c54edcbd2879428d657708be9a2ab372aa66e4792886"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-timeline-controls.json",
|
||||
"sha256": "6a86b07770f1cd8d758334fb61c46254197a7f533d24c056fc9a52c317488291"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-timeline.md",
|
||||
"sha256": "612dc3ec4c3d435888055ba20a7f28230ce89ea8b071b8c38d1ea2c147074a96"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-transcript-controls.json",
|
||||
"sha256": "9e4dbdc33806d6fcc912dc3aacc8691a77939e2ce2403032b2a8127c0e407e94"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-transcript.md",
|
||||
"sha256": "9e4ac8c92a3a9eca727c29a77ae428702d19ecdee0cab0e3dfcda0a36bf004db"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui.md",
|
||||
"sha256": "896b9928af85a4c7d588dfca93484980aadb238bd79d8142e671c62f0b191fa8"
|
||||
}
|
||||
],
|
||||
"ownerRestoredToBaseGitBytes": true,
|
||||
"productionLinesChanged": 0
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
# Test audit, Round 7 UI — Issue detail default feature gates follow-up
|
||||
|
||||
This separate packet removes **1 registered executions, 1 root renders and 11 net test lines** from `ui/src/pages/IssueDetail.test.tsx`. It adds no helper and changes no production lines. Audit base: `e3effbb9e5c66b838f67fd487987c8bf1007e413`. Prior committed evidence remains byte-identical. Render/execution savings are per complete-suite invocation; no measured runtime or CI-speed claim is made.
|
||||
|
||||
## Exact retirement map
|
||||
|
||||
| Retired registration | Keeper | Observations retained |
|
||||
|---|---|---|
|
||||
| `hides file viewer entry points by default` | `hides the plan decomposition panel by default` | expect( container.querySelector('[aria-label="Open file in this issue"]'), ).toBeNull(); |
|
||||
|
||||
IssueDetail.tsx derives fileViewerEnabled and showPlanDecompositionsSection independently from instance settings. The identical default issue/render/two-flush setup already proves the plan panel absent and no listAcceptedPlanDecompositions API request. It now also retains the exact file-entry-point absence guard. The actual IssuePlanDecompositionsSection owns its list API request only when mounted. Enabled file viewer, enabled plan decomposition, routing/hash and interactive viewer states remain distinct and unchanged.
|
||||
|
||||
The AST verifier checks exact setup, shared enclosing hooks and matched cleanup where present, reconstructs candidate text solely from the declared registrations/assertion migrations, and requires exact byte equality plus full-program AST equality outside those edits. No fixture, helper, provider, action order, wait, assertion strength, timer or teardown changes. The IssueChatThread keeper is an existing complete subset proof; InlineEditor’s identical not-null guard is retained once. Every other case stays byte-identical. Default CI includes this file in `@paperclipai/ui` under `general-workspaces-a`, once across the two file shards; workflow/config unchanged.
|
||||
|
||||
## Complete owner-file results
|
||||
|
||||
| Run | Registered | Passed | Failed | Skipped |
|
||||
|---|---:|---:|---:|---:|
|
||||
| Baseline | 141 | 141 | 0 | 0 |
|
||||
| Candidate | 140 | 140 | 0 | 0 |
|
||||
|
||||
From `ui/`: `pnpm exec vitest run src/pages/IssueDetail.test.tsx`.
|
||||
|
||||
All 1 isolated positive controls passed. All 1 deliberate behavior regressions failed at their intended retained/migrated assertion, rather than setup, timeout or a different guard:
|
||||
|
||||
| Regression | Intended guard |
|
||||
|---|---|
|
||||
| file-viewer | `container.querySelector('[aria-label="Open file in this issue"]')` |
|
||||
|
||||
Exactly one production owner was temporarily changed per control. Every owner was restored byte for byte after each mutation and matched pinned Git bytes. Filtered controls select one keeper; unselected tests do not count as full-suite evidence. [Controls JSON](2026-10-12-test-audit-r7-ui-issuedetail-controls.json) records exact owner/source hashes, migration/input proof, complete-file run/log digests, mutation bodies, intended assertion failures and restoration receipts. Temporary raw verifiers and logs are identified by digests rather than committed in full.
|
||||
|
||||
The earlier broad `pnpm test:run` was intentionally stopped without completion and is not claimed as passed. Separate packet results are focused proof, not a completed combined delivery-head replay or pending full CI. No push, rebase, PR or merge is included here.
|
||||
@@ -0,0 +1,549 @@
|
||||
{
|
||||
"audit": {
|
||||
"file": "ui/src/components/OnboardingWizard.test.tsx",
|
||||
"base": "2e76f5157240ee8b2d42adbdcd4c345aea07c013",
|
||||
"originalSha256": "6215ee2f034686deaf2d6091590030dcdeccff1697422574e45e0351eaf5a7fe",
|
||||
"candidateSha256": "a2be5c51e61cffe1e6a01e281e073b766d7a2c18a2eb9795cfa0810d0cf9531d",
|
||||
"allOtherProgramAstUnchanged": true,
|
||||
"allOtherSourceBytesUnchanged": true,
|
||||
"newHelpers": 0,
|
||||
"registeredInvocationsRemoved": 5,
|
||||
"renderInvocationsRemoved": 5,
|
||||
"setupInvocationsRemoved": 5,
|
||||
"netTestLinesRemoved": 56,
|
||||
"migrations": [
|
||||
{
|
||||
"retired": "carries no token value in the hire payload",
|
||||
"keeper": "sends the fixed Claude binding and applyStoredClaudeLogin when a stored login exists",
|
||||
"exactLeadingStatements": 4,
|
||||
"sameEnclosingHooks": true,
|
||||
"explicitCleanupAstEqual": true,
|
||||
"kind": "privacy",
|
||||
"exactMigratedStatements": [
|
||||
"const binding = hireBody.adapterConfig.env?.[CLAUDE_OAUTH_TOKEN_ENV_KEY] as\n | { type: string }\n | undefined;",
|
||||
"expect(binding?.type).toBe(\"user_secret_ref\");",
|
||||
"expect(JSON.stringify(hireBody)).not.toContain(\"secretId\");"
|
||||
],
|
||||
"alreadyExactKeeperStatementsOrBindings": [
|
||||
"expect(mockAgentsApi.hire).toHaveBeenCalled();",
|
||||
"const hireArgs = mockAgentsApi.hire.mock.calls.at(-1) as unknown[];",
|
||||
"const hireBody = hireArgs[1] as { adapterConfig: { env?: Record<string, unknown> } };"
|
||||
],
|
||||
"registeredInvocationsRemoved": 1,
|
||||
"renderInvocationsRemoved": 1,
|
||||
"setupInvocationsRemoved": 1
|
||||
},
|
||||
{
|
||||
"retired": "sends the fixed binding in the environment test request when the status route returns 200",
|
||||
"keeper": "sends the fixed Claude binding and applyStoredClaudeLogin when a stored login exists",
|
||||
"exactLeadingStatements": 4,
|
||||
"sameEnclosingHooks": true,
|
||||
"explicitCleanupAstEqual": true,
|
||||
"kind": "probe",
|
||||
"exactMigratedStatements": [
|
||||
"expect(mockAgentsApi.testEnvironment).toHaveBeenCalled();",
|
||||
"const testArgs = mockAgentsApi.testEnvironment.mock.calls.at(-1) as unknown[];",
|
||||
"const testBody = testArgs[2] as { adapterConfig: { env?: Record<string, unknown> } };",
|
||||
"expect(testBody.adapterConfig.env?.[CLAUDE_OAUTH_TOKEN_ENV_KEY]).toEqual({\n type: \"user_secret_ref\",\n key: CLAUDE_OAUTH_TOKEN_ENV_KEY,\n version: \"latest\",\n required: true,\n });"
|
||||
],
|
||||
"alreadyExactKeeperStatementsOrBindings": [],
|
||||
"registeredInvocationsRemoved": 1,
|
||||
"renderInvocationsRemoved": 1,
|
||||
"setupInvocationsRemoved": 1
|
||||
},
|
||||
{
|
||||
"retired": "sends no binding in the environment test request when the status route returns 404",
|
||||
"keeper": "sends no binding and no flag when the Claude status route returns 404",
|
||||
"exactLeadingStatements": 2,
|
||||
"sameEnclosingHooks": true,
|
||||
"explicitCleanupAstEqual": true,
|
||||
"kind": "probe",
|
||||
"exactMigratedStatements": [
|
||||
"expect(mockAgentsApi.testEnvironment).toHaveBeenCalled();",
|
||||
"const testArgs = mockAgentsApi.testEnvironment.mock.calls.at(-1) as unknown[];",
|
||||
"const testBody = testArgs[2] as { adapterConfig: { env?: Record<string, unknown> } };",
|
||||
"expect(testBody.adapterConfig.env?.[CLAUDE_OAUTH_TOKEN_ENV_KEY]).toBeUndefined();"
|
||||
],
|
||||
"alreadyExactKeeperStatementsOrBindings": [],
|
||||
"registeredInvocationsRemoved": 1,
|
||||
"renderInvocationsRemoved": 1,
|
||||
"setupInvocationsRemoved": 1
|
||||
},
|
||||
{
|
||||
"retired": "creates the organization on Continue and lands on the agent step, no mission",
|
||||
"keeper": "shows no environment-check card on the model step, and no Mission row on review",
|
||||
"exactLeadingStatements": 3,
|
||||
"sameEnclosingHooks": true,
|
||||
"explicitCleanupAstEqual": true,
|
||||
"kind": "company",
|
||||
"exactMigratedStatements": [
|
||||
"expect(mockCompaniesApi.create).toHaveBeenCalledWith({ name: \"Initech\" });",
|
||||
"expect(document.body.textContent).not.toContain(\"Define your mission\");",
|
||||
"expect(document.body.textContent).not.toContain(\"Tell us about your team\");"
|
||||
],
|
||||
"alreadyExactKeeperStatementsOrBindings": [
|
||||
"expect(document.body.textContent).toContain(\"Create your first agent\");"
|
||||
],
|
||||
"registeredInvocationsRemoved": 1,
|
||||
"renderInvocationsRemoved": 1,
|
||||
"setupInvocationsRemoved": 1
|
||||
},
|
||||
{
|
||||
"retired": "renders no 'Use saved login' control",
|
||||
"keeper": "starts the other source's login after backing out of the first",
|
||||
"exactLeadingStatements": 3,
|
||||
"sameEnclosingHooks": true,
|
||||
"explicitCleanupAstEqual": true,
|
||||
"kind": "normal",
|
||||
"exactMigratedStatements": [
|
||||
"expect(document.body.textContent).toContain(\"Sign in to Claude then come back and enter authorization code\");",
|
||||
"expect(document.body.textContent).not.toContain(\"Use saved login\");"
|
||||
],
|
||||
"alreadyExactKeeperStatementsOrBindings": [],
|
||||
"registeredInvocationsRemoved": 1,
|
||||
"renderInvocationsRemoved": 1,
|
||||
"setupInvocationsRemoved": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"verifierSha256": "ff07f5e2e308cfc0f26584a6cd6599bcd98665e79d7f4782ed5bb36b35cb8cb9",
|
||||
"mutationVerifierSha256": "676b973d4838ed130c5ae92d4bc50fb32a65309af8c858450ec34bcce13729e9",
|
||||
"runs": [
|
||||
{
|
||||
"kind": "baseline",
|
||||
"total": 93,
|
||||
"passed": 93,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"jsonSha256": "647b2b743bba5c5fe87cf8b19b413bfa811867cb19cd2d0afd0e0e64f4989603",
|
||||
"logSha256": "b83f2bc12966793c3f000e579f0f938011b715572bc5caa2f23c144cfa23e7c5"
|
||||
},
|
||||
{
|
||||
"kind": "candidate",
|
||||
"total": 88,
|
||||
"passed": 88,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"jsonSha256": "3d708b8681916868d4e03d569e89038082e25c899e0f95935d9ea1903a364ce9",
|
||||
"logSha256": "e015a19efabf22acd715d06ac5dda923a4f5bf11926089fe762db4e20e39f561"
|
||||
}
|
||||
],
|
||||
"mutations": [
|
||||
{
|
||||
"slug": "probe-present-200",
|
||||
"owner": "ui/src/components/OnboardingWizard.tsx",
|
||||
"sourceSha256": "22a2c8bfbe0aa02ea1ab13a95fad511760f4c2cf69c2e875af4f7c4bbd3c4861",
|
||||
"title": "sends the fixed Claude binding and applyStoredClaudeLogin when a stored login exists",
|
||||
"mutation": {
|
||||
"before": "const result = await agentsApi.testEnvironment(\n createdCompanyId,\n adapterType,\n {\n adapterConfig: adapterConfigOverride ?? buildAdapterConfig(),\n ...(managedBindingForStep() ? { aiConnection: managedBindingForStep() } : {}),\n environmentId,\n }\n );",
|
||||
"after": "const result = { adapterType, status: \"pass\" as const, checks: [], testedAt: new Date(0).toISOString() };",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(mockAgentsApi.testEnvironment).toHaveBeenCalled()",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "31743b16d52bc74738877f45c4d52400bd9fc9e105fc59b7ec4804906969ec98",
|
||||
"logSha256": "d80825ed43906d24b6d325af1009b5d538e0cd9d8b52a5760c996f7cc7e1b34c",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "384a0396090744b528b532ad60ceece8882cc84eb1c554e1e59b0603942323dd",
|
||||
"logSha256": "9f2c7c7ba8a4331469c7b7bd262c2657daabe0dfddd5a106882d9ed08600d8a1",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected \"vi.fn()\" to be called at least once\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:2214:51)\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:1944:14)\n at Proxy.methodWrapper (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/chai@6.3.0/node_modules/chai/index.js:1737:25)\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/OnboardingWizard.test.tsx:1044:45\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "probe-binding-200",
|
||||
"owner": "ui/src/components/OnboardingWizard.tsx",
|
||||
"sourceSha256": "22a2c8bfbe0aa02ea1ab13a95fad511760f4c2cf69c2e875af4f7c4bbd3c4861",
|
||||
"title": "sends the fixed Claude binding and applyStoredClaudeLogin when a stored login exists",
|
||||
"mutation": {
|
||||
"before": "adapterConfig: adapterConfigOverride ?? buildAdapterConfig(),",
|
||||
"after": "adapterConfig: { ...(adapterConfigOverride ?? buildAdapterConfig()), env: {} },",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(testBody.adapterConfig.env?.[CLAUDE_OAUTH_TOKEN_ENV_KEY]).toEqual(",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "81c27fbb8cba0dcf5b7bdf2ce2c97aab35616ff5e6f1a969aaf30e22c2593e11",
|
||||
"logSha256": "ca107f788a76c3d6646d58e82f4a9c6e2df72bb74e82de2597298c2502e33bff",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "46182474cf2dbeaf39f7bcad775b9b45aa0d5522998d11489c864642878d5ba5",
|
||||
"logSha256": "7ffcbe62fc7de0402029a8fc92840b7c5fc17ed5d4a72d8ceab5235967c47416",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected undefined to deeply equal { type: 'user_secret_ref', \u2026(3) }\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/OnboardingWizard.test.tsx:1047:72\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "hire-reference-kind",
|
||||
"owner": "ui/src/components/OnboardingWizard.tsx",
|
||||
"sourceSha256": "22a2c8bfbe0aa02ea1ab13a95fad511760f4c2cf69c2e875af4f7c4bbd3c4861",
|
||||
"title": "sends the fixed Claude binding and applyStoredClaudeLogin when a stored login exists",
|
||||
"mutation": {
|
||||
"before": "adapterConfig: hireAdapterConfig,",
|
||||
"after": "adapterConfig: { ...hireAdapterConfig, env: { ...(hireAdapterConfig.env ?? {}), [\"CLAUDE_CODE_OAUTH_TOKEN\"]: { type: \"plain\", value: \"wrong-kind\" } } },",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(binding?.type).toBe(\"user_secret_ref\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "7b4f481d6c0f365bf00f5713ff2203cff0642575c11ccb3911b9707ea8f54ef5",
|
||||
"logSha256": "628ee5cd5995a7b11df381f985db1757fca8ef85710603e06fd259cfb8515c0a",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "d231ee320ece943d41cefd9b1d01eb1d8b136c14be04b93e8b0e135e6eb7e294",
|
||||
"logSha256": "4b97d9537eabe304eadc0b82144acfaba7bc1088edc74ab915170cc6f23f907b",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected 'plain' to be 'user_secret_ref' // Object.is equality\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/OnboardingWizard.test.tsx:1064:29\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "hire-private-id",
|
||||
"owner": "ui/src/components/OnboardingWizard.tsx",
|
||||
"sourceSha256": "22a2c8bfbe0aa02ea1ab13a95fad511760f4c2cf69c2e875af4f7c4bbd3c4861",
|
||||
"title": "sends the fixed Claude binding and applyStoredClaudeLogin when a stored login exists",
|
||||
"mutation": {
|
||||
"before": "adapterConfig: hireAdapterConfig,",
|
||||
"after": "adapterConfig: hireAdapterConfig,\n secretId: \"leaked-reference-id\",",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(JSON.stringify(hireBody)).not.toContain(\"secretId\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "c31e4abc66b53c0e2a0a1d670e8a5c09b4e5737e118299a7d7b62eec720fa6d2",
|
||||
"logSha256": "5c3083595d2bf2f06f52668806ecf9e412059f1da5186ecb932532adbde2c655",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "b98037a4460a3e20efa63527204996fbbc8ecdb67d921af4ac32c04cca22d58a",
|
||||
"logSha256": "29bed62b4bf4fb4d9a9aa9309fc5ebcddc8c73edd704933df4963dd401073262",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected '{\"name\":\"Ada\",\"appearance\":{\"schemaVe\u2026' not to contain 'secretId'\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/OnboardingWizard.test.tsx:1065:44\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "probe-present-404",
|
||||
"owner": "ui/src/components/OnboardingWizard.tsx",
|
||||
"sourceSha256": "22a2c8bfbe0aa02ea1ab13a95fad511760f4c2cf69c2e875af4f7c4bbd3c4861",
|
||||
"title": "sends no binding and no flag when the Claude status route returns 404",
|
||||
"mutation": {
|
||||
"before": "const result = await agentsApi.testEnvironment(\n createdCompanyId,\n adapterType,\n {\n adapterConfig: adapterConfigOverride ?? buildAdapterConfig(),\n ...(managedBindingForStep() ? { aiConnection: managedBindingForStep() } : {}),\n environmentId,\n }\n );",
|
||||
"after": "const result = { adapterType, status: \"pass\" as const, checks: [], testedAt: new Date(0).toISOString() };",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(mockAgentsApi.testEnvironment).toHaveBeenCalled()",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "4d38c478ca455f244954d02107699d6af5614dfb8c80f553da1caf15f0dafd5a",
|
||||
"logSha256": "0d6a237b79947cd1b028a87b34e2cc4d28755194e54ee73fffa6cbb99a530488",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "68f321ac5807be15bc85e58e1adeab127485cbb17d62e540ec0ff415ff8c5d60",
|
||||
"logSha256": "09d6f75954ccc52b7fefb1747f3d5d54a70f952c509e5971959de4b96e47515b",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected \"vi.fn()\" to be called at least once\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:2214:51)\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:1944:14)\n at Proxy.methodWrapper (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/chai@6.3.0/node_modules/chai/index.js:1737:25)\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/OnboardingWizard.test.tsx:1085:45\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "probe-binding-404",
|
||||
"owner": "ui/src/components/OnboardingWizard.tsx",
|
||||
"sourceSha256": "22a2c8bfbe0aa02ea1ab13a95fad511760f4c2cf69c2e875af4f7c4bbd3c4861",
|
||||
"title": "sends no binding and no flag when the Claude status route returns 404",
|
||||
"mutation": {
|
||||
"before": "adapterConfig: adapterConfigOverride ?? buildAdapterConfig(),",
|
||||
"after": "adapterConfig: { ...(adapterConfigOverride ?? buildAdapterConfig()), env: { [\"CLAUDE_CODE_OAUTH_TOKEN\"]: { type: \"user_secret_ref\", key: \"CLAUDE_CODE_OAUTH_TOKEN\", version: \"latest\", required: true } } },",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(testBody.adapterConfig.env?.[CLAUDE_OAUTH_TOKEN_ENV_KEY]).toBeUndefined()",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "3f40b447122e687985096e3af6f8e2a5a8cad624904d034874ace9a7925fbe09",
|
||||
"logSha256": "84548520fda7a059de5f0d4b835b3df59477c69ccc199b2f9eaa10f35c2d5402",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "2223afa8cb0fef009b6b58ef34d5a0d4cb587efb1842f151c362b5d43cfc3086",
|
||||
"logSha256": "4966efcc558d90d72e14d397901b306565dede76b0b908edbbbf223c48d9ac1d",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected { type: 'user_secret_ref', \u2026(3) } to be undefined\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/OnboardingWizard.test.tsx:1088:72\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "create-company-name",
|
||||
"owner": "ui/src/components/OnboardingWizard.tsx",
|
||||
"sourceSha256": "22a2c8bfbe0aa02ea1ab13a95fad511760f4c2cf69c2e875af4f7c4bbd3c4861",
|
||||
"title": "shows no environment-check card on the model step, and no Mission row on review",
|
||||
"mutation": {
|
||||
"before": "companiesApi.create({ name: companyName.trim() })",
|
||||
"after": "companiesApi.create({ name: \"Wrong company\" })",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(mockCompaniesApi.create).toHaveBeenCalledWith({ name: \"Initech\" })",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "4bd6223a943a9f88351a1163a68267c20a57907c0f685a804f42134df7d418b9",
|
||||
"logSha256": "d6e0fc1cd39e843cef3ab559a562dfda70ea826456904fcb4199b41d22616682",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "43cb71ec93702eefdb0c1332d80e25d163629a5e27a1f67a8c4d2990013f01e0",
|
||||
"logSha256": "07b461cd0a99e77e8f3e8c668613a67eb3f19ab622628cfa6b6058fb8e1dbb31",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected \"vi.fn()\" to be called with arguments: [ { name: 'Initech' } ]\n\nReceived:\n\n 1st vi.fn() call:\n\n [\n {\n- \"name\": \"Initech\",\n+ \"name\": \"Wrong company\",\n },\n ]\n\n\nNumber of calls: 1\n\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:2233:10)\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:1944:14)\n at Proxy.methodWrapper (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/chai@6.3.0/node_modules/chai/index.js:1737:25)\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/OnboardingWizard.test.tsx:462:39\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "initial-mission",
|
||||
"owner": "ui/src/components/OnboardingWizard.tsx",
|
||||
"sourceSha256": "22a2c8bfbe0aa02ea1ab13a95fad511760f4c2cf69c2e875af4f7c4bbd3c4861",
|
||||
"title": "shows no environment-check card on the model step, and no Mission row on review",
|
||||
"mutation": {
|
||||
"before": "\"Create your first agent\"",
|
||||
"after": "\"Create your first agent \u2014 Define your mission\"",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(document.body.textContent).not.toContain(\"Define your mission\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "59d05408e1ca40f733f09b3a0a4f3006c6717056a54e08f1e5da4543aa6b5446",
|
||||
"logSha256": "593772fcb849cf4afb7bbfc4a38164983b22229c9069663d65f059e7e60e43c7",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "cfd65b2c01b74f4e82db621b0987dbb7894ff6b7a9159f7ab4d2964bb0ee987b",
|
||||
"logSha256": "ba59a142a703fbcfb915dea3365a1e72283c9b7acdb28b7f486ee2949411ad04",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected 'Step 2 of 4 Create your first agent \u2026' not to contain 'Define your mission'\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/OnboardingWizard.test.tsx:463:45\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "initial-team",
|
||||
"owner": "ui/src/components/OnboardingWizard.tsx",
|
||||
"sourceSha256": "22a2c8bfbe0aa02ea1ab13a95fad511760f4c2cf69c2e875af4f7c4bbd3c4861",
|
||||
"title": "shows no environment-check card on the model step, and no Mission row on review",
|
||||
"mutation": {
|
||||
"before": "\"Create your first agent\"",
|
||||
"after": "\"Create your first agent \u2014 Tell us about your team\"",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(document.body.textContent).not.toContain(\"Tell us about your team\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "a5a285c51d9f2d943310b9434bdcaa81a12d3c07384c86ae6b509f176359c359",
|
||||
"logSha256": "d37342c66155290e327442b45115f0174acce8c5f6ab05844f75c6382480b0fb",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "e80732591e8829b5712e5714a1195b44c95d00f8d211f16b37360892dde3f66e",
|
||||
"logSha256": "7ebb5382e5d3701c63233f2c9ffe01bb7a0add3adac6b160ed70b3cbd185f9cd",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected 'Step 2 of 4 Create your first agent \u2026' not to contain 'Tell us about your team'\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/OnboardingWizard.test.tsx:464:45\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "auth-instruction",
|
||||
"owner": "ui/src/components/AdapterLoginChrome.tsx",
|
||||
"sourceSha256": "7fe56ca349b17410287074f89a42373b8d46280adb580a57067253ba45f00499",
|
||||
"title": "starts the other source's login after backing out of the first",
|
||||
"mutation": {
|
||||
"before": "? \" then come back and enter authorization code\"",
|
||||
"after": "? \" then return\"",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(document.body.textContent).toContain(\"Sign in to Claude then come back and enter authorization code\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "4154830e1db482e7b7be3bc29a90a305886135615e4931b4cc3ab94131a782c3",
|
||||
"logSha256": "425b312c4684680caf805e055b467180d71771928739fb2fb0bc884c5816db90",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "159827cd6b9ff90b04bd8fad88d06d70b981a49439d21d766a581845a3bc0905",
|
||||
"logSha256": "36c516fa3a6507b036edd82a58808b69ec8a0ec6bd5870d0103908edcb173473",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected 'Step 2 of 3Ada Connect a modelPapercl\u2026' to contain 'Sign in to Claude then come back and \u2026'\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/OnboardingWizard.test.tsx:2839:41\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "saved-login",
|
||||
"owner": "ui/src/components/AdapterLoginChrome.tsx",
|
||||
"sourceSha256": "7fe56ca349b17410287074f89a42373b8d46280adb580a57067253ba45f00499",
|
||||
"title": "starts the other source's login after backing out of the first",
|
||||
"mutation": {
|
||||
"before": ": \" by providing the authorization code below\"}",
|
||||
"after": ": \" by providing the authorization code below\"}\n <button>Use saved login</button>",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(document.body.textContent).not.toContain(\"Use saved login\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "133ee3765d37cd8af631b422c60109dddbe698d3e6b699793552af48bcd4b8ba",
|
||||
"logSha256": "d692064dd8957fe9868fb507be75364c6db3412f727978f894cee91e3a1ba672",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "122fed92c9caa458fa52e0a4b84524f8bcb64545e0578597430f645b47adec69",
|
||||
"logSha256": "717f13481ecc00acbf9531e1e9a3c8c04c46d04f148f97b918d9137854a6593e",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected 'Step 2 of 3Ada Connect a modelPapercl\u2026' not to contain 'Use saved login'\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/OnboardingWizard.test.tsx:2840:45\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"priorEvidenceUnchanged": [
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-agentconfig-controls.json",
|
||||
"sha256": "cfb4357610beaa464cdb26848f74a7b8d967d6409c63dbd6821c92886a9cf980"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-agentconfig.md",
|
||||
"sha256": "ea6d5dfc8cedcd653edd55ca9d77568431413a351f4de5db77ca6ac8f22b051a"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appboundary-controls.json",
|
||||
"sha256": "bad49e7bc92dea919df6b980bfa45e7452984cf31a6fd4655b355ba0444ff9a6"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appboundary.md",
|
||||
"sha256": "cd6f173584db0d485004af6f85b1ce78fa65b19d8c6ef582b061f0d232c6c1ed"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appdetail-controls.json",
|
||||
"sha256": "7906fde0d62e14a7511b5cf45f864c9386a4c377922333eefc7f7e703c832f6a"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appdetail.md",
|
||||
"sha256": "715f23cd27502c92d0f5d1b83b91bcac03f254c73ab63b44181ae76939805229"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-attachments-controls.json",
|
||||
"sha256": "c4ff66a3226e1edafd286cad0ca45c9445795b46944cf70d606c59a754913f3a"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-attachments.md",
|
||||
"sha256": "d38715393c95306d10e871a5a2c9a32f105fa1452871cd7ad030d86dbbdb7416"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-controls.json",
|
||||
"sha256": "0d445f6f066032f2d9cd724525a8d7d2290246cbfeee1f6ab4b44818467af2a7"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-experimental-controls.json",
|
||||
"sha256": "9c72abee7ee1a937fdbd6ccee870320308bc7ce06b4fc1e338cd9bd3b0efba6b"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-experimental.md",
|
||||
"sha256": "93b7583a8ebba39dc97e390918fd62029955a00beda22756f55bd6374acc3737"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-inline-controls.json",
|
||||
"sha256": "af9d3f115e6e0518c2c0a2e11b8913e7aa82a35c848f114e6750884323601e17"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-inline.md",
|
||||
"sha256": "52d8e27970bd1c091ae7edf403b2331e921081da9198270df65ff779a8efc1bc"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-issuechat-controls.json",
|
||||
"sha256": "45d86fa901c8ab40bc3fe98d266e3ba1a7bbc93edb7bc2aae60ccd9bfa130c37"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-issuechat.md",
|
||||
"sha256": "15e84a553c5a468aea013941f68d3aa517bfb5a13ae296a90e1a39586f85de8e"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-issuedetail-controls.json",
|
||||
"sha256": "a56f183f1c6b940662db0c4bfb62457eda0cec453c2019b439ec716ed9d2a3e1"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-issuedetail.md",
|
||||
"sha256": "e137af5b991c936a167d6ad6f3c710b99688e939f839b163b203259fc998ded8"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-route-controls.json",
|
||||
"sha256": "0a72a7770ec749f2c0507a74d395e65d70b722d0b9d2a767a2c066a67ed46382"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-route.md",
|
||||
"sha256": "9b5e1543163d6c9d0958aa3e377a593ec458f6674ce1ddb2bf3ca158786f09c4"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-sidebar-controls.json",
|
||||
"sha256": "ae9f24746e67432cf6247c5da130b9c1bba46fc85112c0610d3f18545dfce326"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-sidebar.md",
|
||||
"sha256": "5e267441c43aa8375fa5c54edcbd2879428d657708be9a2ab372aa66e4792886"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-timeline-controls.json",
|
||||
"sha256": "6a86b07770f1cd8d758334fb61c46254197a7f533d24c056fc9a52c317488291"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-timeline.md",
|
||||
"sha256": "612dc3ec4c3d435888055ba20a7f28230ce89ea8b071b8c38d1ea2c147074a96"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-transcript-controls.json",
|
||||
"sha256": "9e4dbdc33806d6fcc912dc3aacc8691a77939e2ce2403032b2a8127c0e407e94"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-transcript.md",
|
||||
"sha256": "9e4ac8c92a3a9eca727c29a77ae428702d19ecdee0cab0e3dfcda0a36bf004db"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui.md",
|
||||
"sha256": "896b9928af85a4c7d588dfca93484980aadb238bd79d8142e671c62f0b191fa8"
|
||||
}
|
||||
],
|
||||
"ownerRestoredToBaseGitBytes": true,
|
||||
"productionLinesChanged": 0
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
{
|
||||
"audit": {
|
||||
"file": "ui/src/components/OnboardingWizard.step.test.tsx",
|
||||
"base": "2e76f5157240ee8b2d42adbdcd4c345aea07c013",
|
||||
"originalSha256": "05f29524e705110bc020285744b4f1be3047ea8ed13eb1e5434013df54762019",
|
||||
"candidateSha256": "6f38d97fc25a6ad573477e3ec00a6509eeb1993c6af0812429b7861091d3ba88",
|
||||
"allOtherProgramAstUnchanged": true,
|
||||
"allOtherSourceBytesUnchanged": true,
|
||||
"newHelpers": 0,
|
||||
"registeredInvocationsRemoved": 1,
|
||||
"renderInvocationsRemoved": 1,
|
||||
"setupInvocationsRemoved": 1,
|
||||
"netTestLinesRemoved": 9,
|
||||
"migrations": [
|
||||
{
|
||||
"retired": "opens on the agent step when the goals lookup fails outright",
|
||||
"keeper": "does not move an open wizard when a later refetch finds a mission",
|
||||
"exactLeadingStatements": 5,
|
||||
"sameEnclosingHooks": true,
|
||||
"explicitCleanupAstEqual": false,
|
||||
"kind": "subset",
|
||||
"exactMigratedStatements": [],
|
||||
"alreadyExactKeeperStatementsOrBindings": [
|
||||
"routerState.pathname = \"/PC1/onboarding\";",
|
||||
"mockGoalsApi.list.mockRejectedValue(new Error(\"goals unavailable\"));",
|
||||
"await render();",
|
||||
"await settle();",
|
||||
"expect(currentStep()).toBe(\"agent\");"
|
||||
],
|
||||
"registeredInvocationsRemoved": 1,
|
||||
"renderInvocationsRemoved": 1,
|
||||
"setupInvocationsRemoved": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"verifierSha256": "ff07f5e2e308cfc0f26584a6cd6599bcd98665e79d7f4782ed5bb36b35cb8cb9",
|
||||
"mutationVerifierSha256": "676b973d4838ed130c5ae92d4bc50fb32a65309af8c858450ec34bcce13729e9",
|
||||
"runs": [
|
||||
{
|
||||
"kind": "baseline",
|
||||
"total": 14,
|
||||
"passed": 14,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"jsonSha256": "97d067fe55e610e4c0d63f7ba0d7eab05ebe7d1a303248a616d01dd04f95015e",
|
||||
"logSha256": "6e010087718c28d08d3f4a426280526bc8f760ff28984d5205eb18fa41d5b752"
|
||||
},
|
||||
{
|
||||
"kind": "candidate",
|
||||
"total": 13,
|
||||
"passed": 13,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"jsonSha256": "28eb77c49492b068be69a761fac2139788e49e78032473692dc37fbfbc0d56cd",
|
||||
"logSha256": "fb8dcd4aafa59b414e1394dca9682a3f50c70bf567bb26086498d4b4fca9eb60"
|
||||
}
|
||||
],
|
||||
"mutations": [
|
||||
{
|
||||
"slug": "initial-agent-step",
|
||||
"owner": "ui/src/components/OnboardingWizard.tsx",
|
||||
"sourceSha256": "22a2c8bfbe0aa02ea1ab13a95fad511760f4c2cf69c2e875af4f7c4bbd3c4861",
|
||||
"title": "does not move an open wizard when a later refetch finds a mission",
|
||||
"mutation": {
|
||||
"before": "setStep(initialStepRef.current);",
|
||||
"after": "setStep(4);",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(currentStep()).toBe(\"agent\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "fb177a7674f0ad536aee811dbf0dbf02e7d3cb4db65ad80e274901b3db53613d",
|
||||
"logSha256": "1afc3859f49727677ef5f0edfd5e77d15110136b154fe1c93b3bc2196b569daf",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "867f486c5b06f88c22e43d49aca66bd535b7c2d7b5e7b66c2e67db8b9a9b18c3",
|
||||
"logSha256": "cbc50ca1569ffab283e25d0106fcdbd4540d4006a6ba872aef20aefc5339972e",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected 'other' to be 'agent' // Object.is equality\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/OnboardingWizard.step.test.tsx:305:27\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"priorEvidenceUnchanged": [
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-agentconfig-controls.json",
|
||||
"sha256": "cfb4357610beaa464cdb26848f74a7b8d967d6409c63dbd6821c92886a9cf980"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-agentconfig.md",
|
||||
"sha256": "ea6d5dfc8cedcd653edd55ca9d77568431413a351f4de5db77ca6ac8f22b051a"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appboundary-controls.json",
|
||||
"sha256": "bad49e7bc92dea919df6b980bfa45e7452984cf31a6fd4655b355ba0444ff9a6"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appboundary.md",
|
||||
"sha256": "cd6f173584db0d485004af6f85b1ce78fa65b19d8c6ef582b061f0d232c6c1ed"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appdetail-controls.json",
|
||||
"sha256": "7906fde0d62e14a7511b5cf45f864c9386a4c377922333eefc7f7e703c832f6a"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appdetail.md",
|
||||
"sha256": "715f23cd27502c92d0f5d1b83b91bcac03f254c73ab63b44181ae76939805229"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-attachments-controls.json",
|
||||
"sha256": "c4ff66a3226e1edafd286cad0ca45c9445795b46944cf70d606c59a754913f3a"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-attachments.md",
|
||||
"sha256": "d38715393c95306d10e871a5a2c9a32f105fa1452871cd7ad030d86dbbdb7416"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-controls.json",
|
||||
"sha256": "0d445f6f066032f2d9cd724525a8d7d2290246cbfeee1f6ab4b44818467af2a7"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-experimental-controls.json",
|
||||
"sha256": "9c72abee7ee1a937fdbd6ccee870320308bc7ce06b4fc1e338cd9bd3b0efba6b"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-experimental.md",
|
||||
"sha256": "93b7583a8ebba39dc97e390918fd62029955a00beda22756f55bd6374acc3737"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-inline-controls.json",
|
||||
"sha256": "af9d3f115e6e0518c2c0a2e11b8913e7aa82a35c848f114e6750884323601e17"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-inline.md",
|
||||
"sha256": "52d8e27970bd1c091ae7edf403b2331e921081da9198270df65ff779a8efc1bc"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-issuechat-controls.json",
|
||||
"sha256": "45d86fa901c8ab40bc3fe98d266e3ba1a7bbc93edb7bc2aae60ccd9bfa130c37"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-issuechat.md",
|
||||
"sha256": "15e84a553c5a468aea013941f68d3aa517bfb5a13ae296a90e1a39586f85de8e"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-issuedetail-controls.json",
|
||||
"sha256": "a56f183f1c6b940662db0c4bfb62457eda0cec453c2019b439ec716ed9d2a3e1"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-issuedetail.md",
|
||||
"sha256": "e137af5b991c936a167d6ad6f3c710b99688e939f839b163b203259fc998ded8"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-route-controls.json",
|
||||
"sha256": "0a72a7770ec749f2c0507a74d395e65d70b722d0b9d2a767a2c066a67ed46382"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-route.md",
|
||||
"sha256": "9b5e1543163d6c9d0958aa3e377a593ec458f6674ce1ddb2bf3ca158786f09c4"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-sidebar-controls.json",
|
||||
"sha256": "ae9f24746e67432cf6247c5da130b9c1bba46fc85112c0610d3f18545dfce326"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-sidebar.md",
|
||||
"sha256": "5e267441c43aa8375fa5c54edcbd2879428d657708be9a2ab372aa66e4792886"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-timeline-controls.json",
|
||||
"sha256": "6a86b07770f1cd8d758334fb61c46254197a7f533d24c056fc9a52c317488291"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-timeline.md",
|
||||
"sha256": "612dc3ec4c3d435888055ba20a7f28230ce89ea8b071b8c38d1ea2c147074a96"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-transcript-controls.json",
|
||||
"sha256": "9e4dbdc33806d6fcc912dc3aacc8691a77939e2ce2403032b2a8127c0e407e94"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-transcript.md",
|
||||
"sha256": "9e4ac8c92a3a9eca727c29a77ae428702d19ecdee0cab0e3dfcda0a36bf004db"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui.md",
|
||||
"sha256": "896b9928af85a4c7d588dfca93484980aadb238bd79d8142e671c62f0b191fa8"
|
||||
}
|
||||
],
|
||||
"ownerRestoredToBaseGitBytes": true,
|
||||
"productionLinesChanged": 0
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
# Test audit, Round 7 UI — Onboarding initial step follow-up
|
||||
|
||||
This separate packet removes **1 registered executions, 1 rendered scenarios and 9 net test lines** from `ui/src/components/OnboardingWizard.step.test.tsx`. It adds no helper and changes no production lines. Audit base: `2e76f5157240ee8b2d42adbdcd4c345aea07c013`. All prior committed proof remains byte-identical. Registration/render savings are per complete-suite invocation; no measured runtime or CI-speed claim is made. A service-worker retirement counts only initializer setup, never a render.
|
||||
|
||||
## Exact retirement map
|
||||
|
||||
| Retired registration | Keeper | Exact observations migrated |
|
||||
|---|---|---|
|
||||
| `opens on the agent step when the goals lookup fails outright` | `does not move an open wizard when a later refetch finds a mission` | |
|
||||
|
||||
The retired complete five-statement body is an exact leading AST subset of the keeper, including the rejected goals mock, real route render, settle and agent-step assertion. The keeper is unchanged and then checks a later mission-cache update. Wizard opening/step effects and the real route resolver remain under test; explicit step, company change, reopen and in-flow behavior stay distinct. Existing global teardown remains unchanged.
|
||||
|
||||
The verifier requires matching setup statements, enclosing hooks and explicit teardown where present. It reconstructs candidate source solely from the declared registrations/assertion migrations and requires exact byte equality plus full-program AST equality outside those edits. Existing shared variable bindings, mock arguments and provider/component inputs remain the same. No other fixture, helper, action order, wait, assertion strength, timer or cleanup changes. Default CI includes the file in `@paperclipai/ui` under `general-workspaces-a`, once across its two file shards, with no workflow/config change.
|
||||
|
||||
## Complete owner-file results
|
||||
|
||||
| Run | Registered | Passed | Failed | Skipped |
|
||||
|---|---:|---:|---:|---:|
|
||||
| Baseline | 14 | 14 | 0 | 0 |
|
||||
| Candidate | 13 | 13 | 0 | 0 |
|
||||
|
||||
From `ui/`: `pnpm exec vitest run src/components/OnboardingWizard.step.test.tsx`.
|
||||
|
||||
All 1 separately selected positive controls passed. All 1 distinct production-owner regressions failed at intended retained/migrated assertions, not setup, timeout or another guard:
|
||||
|
||||
| Regression | Intended guard |
|
||||
|---|---|
|
||||
| initial-agent-step | `expect(currentStep()).toBe("agent")` |
|
||||
|
||||
Exactly one production owner changed per control, and every owner was restored byte for byte after each mutation and checked against pinned Git bytes. Literal keeper-name filters are escaped; unselected cases are not full-suite evidence. The initial first-install receipt verifier mistook emit( for it( and rejected its receipt despite the intended test failure. The declaration-boundary matcher was corrected and that control rerun; the rejected verifier attempt supplies no accepted evidence.
|
||||
|
||||
[Controls JSON](2026-10-12-test-audit-r7-ui-onboarding-step-controls.json) preserves source/owner hashes, exact before/after migrations, matched setup and variable-binding proof, complete-file run/log digests, intended assertion failures and restoration checks. Temporary raw scripts/logs are identified by digests rather than committed in full.
|
||||
|
||||
The earlier broad local `pnpm test:run` was intentionally stopped before completion and is not claimed as passed. These separate focused packets precede delivery-head replay and full CI. This packet includes no push, rebase, PR or merge.
|
||||
@@ -0,0 +1,48 @@
|
||||
# Test audit, Round 7 UI — Onboarding walkthroughs follow-up
|
||||
|
||||
This separate packet removes **5 registered executions, 5 rendered scenarios and 56 net test lines** from `ui/src/components/OnboardingWizard.test.tsx`. It adds no helper and changes no production lines. Audit base: `2e76f5157240ee8b2d42adbdcd4c345aea07c013`. All prior committed proof remains byte-identical. Registration/render savings are per complete-suite invocation; no measured runtime or CI-speed claim is made. A service-worker retirement counts only initializer setup, never a render.
|
||||
|
||||
## Exact retirement map
|
||||
|
||||
| Retired registration | Keeper | Exact observations migrated |
|
||||
|---|---|---|
|
||||
| `carries no token value in the hire payload` | `sends the fixed Claude binding and applyStoredClaudeLogin when a stored login exists` | const binding = hireBody.adapterConfig.env?.[CLAUDE_OAUTH_TOKEN_ENV_KEY] as \| { type: string } \| undefined;; expect(binding?.type).toBe("user_secret_ref");; expect(JSON.stringify(hireBody)).not.toContain("secretId"); |
|
||||
| `sends the fixed binding in the environment test request when the status route returns 200` | `sends the fixed Claude binding and applyStoredClaudeLogin when a stored login exists` | expect(mockAgentsApi.testEnvironment).toHaveBeenCalled();; const testArgs = mockAgentsApi.testEnvironment.mock.calls.at(-1) as unknown[];; const testBody = testArgs[2] as { adapterConfig: { env?: Record<string, unknown> } };; expect(testBody.adapterConfig.env?.[CLAUDE_OAUTH_TOKEN_ENV_KEY]).toEqual({ type: "user_secret_ref", key: CLAUDE_OAUTH_TOKEN_ENV_KEY, version: "latest", required: true, }); |
|
||||
| `sends no binding in the environment test request when the status route returns 404` | `sends no binding and no flag when the Claude status route returns 404` | expect(mockAgentsApi.testEnvironment).toHaveBeenCalled();; const testArgs = mockAgentsApi.testEnvironment.mock.calls.at(-1) as unknown[];; const testBody = testArgs[2] as { adapterConfig: { env?: Record<string, unknown> } };; expect(testBody.adapterConfig.env?.[CLAUDE_OAUTH_TOKEN_ENV_KEY]).toBeUndefined(); |
|
||||
| `creates the organization on Continue and lands on the agent step, no mission` | `shows no environment-check card on the model step, and no Mission row on review` | expect(mockCompaniesApi.create).toHaveBeenCalledWith({ name: "Initech" });; expect(document.body.textContent).not.toContain("Define your mission");; expect(document.body.textContent).not.toContain("Tell us about your team"); |
|
||||
| `renders no 'Use saved login' control` | `starts the other source's login after backing out of the first` | expect(document.body.textContent).toContain("Sign in to Claude then come back and enter authorization code");; expect(document.body.textContent).not.toContain("Use saved login"); |
|
||||
|
||||
Five registrations consolidate within identical enclosing hooks and setup expressions. The stored-login 200 keeper receives the complete probe-called, captured probe payload and full fixed-binding equality before its original hire observations. The original hire-body binding is reused through the same captured mock-call expression; its broader type annotation and applyStoredClaudeLogin checks stay unchanged. The retired explicit reference-kind check and complete hire-payload secretId exclusion are retained before the original stronger binding equality. The 404 keeper separately receives its probe-called/captured-body/undefined-binding guards. The organization-create keeper carries exact requested name and both initial mission/team exclusions before advancing. The source-switch keeper carries the Claude instruction anchor and no-legacy-saved-login guard before Back. The real wizard creates companies, probes adapter environments and submits hires through distinct local call sites; its onboarding login UI uses AdapterLoginChrome. No status, provider, stored-login, cancellation or navigation paths are combined. An initial hire-kind mutation referenced an identifier not bound in the wizard and failed before the API payload assertion; it was rejected and restored, then rerun using the actual literal CLAUDE_CODE_OAUTH_TOKEN key. Every other case remains byte-identical.
|
||||
|
||||
The verifier requires matching setup statements, enclosing hooks and explicit teardown where present. It reconstructs candidate source solely from the declared registrations/assertion migrations and requires exact byte equality plus full-program AST equality outside those edits. Existing shared variable bindings, mock arguments and provider/component inputs remain the same. No other fixture, helper, action order, wait, assertion strength, timer or cleanup changes. Default CI includes the file in `@paperclipai/ui` under `general-workspaces-a`, once across its two file shards, with no workflow/config change.
|
||||
|
||||
## Complete owner-file results
|
||||
|
||||
| Run | Registered | Passed | Failed | Skipped |
|
||||
|---|---:|---:|---:|---:|
|
||||
| Baseline | 93 | 93 | 0 | 0 |
|
||||
| Candidate | 88 | 88 | 0 | 0 |
|
||||
|
||||
From `ui/`: `pnpm exec vitest run src/components/OnboardingWizard.test.tsx`.
|
||||
|
||||
All 11 separately selected positive controls passed. All 11 distinct production-owner regressions failed at intended retained/migrated assertions, not setup, timeout or another guard:
|
||||
|
||||
| Regression | Intended guard |
|
||||
|---|---|
|
||||
| probe-present-200 | `expect(mockAgentsApi.testEnvironment).toHaveBeenCalled()` |
|
||||
| probe-binding-200 | `expect(testBody.adapterConfig.env?.[CLAUDE_OAUTH_TOKEN_ENV_KEY]).toEqual(` |
|
||||
| hire-reference-kind | `expect(binding?.type).toBe("user_secret_ref")` |
|
||||
| hire-private-id | `expect(JSON.stringify(hireBody)).not.toContain("secretId")` |
|
||||
| probe-present-404 | `expect(mockAgentsApi.testEnvironment).toHaveBeenCalled()` |
|
||||
| probe-binding-404 | `expect(testBody.adapterConfig.env?.[CLAUDE_OAUTH_TOKEN_ENV_KEY]).toBeUndefined()` |
|
||||
| create-company-name | `expect(mockCompaniesApi.create).toHaveBeenCalledWith({ name: "Initech" })` |
|
||||
| initial-mission | `expect(document.body.textContent).not.toContain("Define your mission")` |
|
||||
| initial-team | `expect(document.body.textContent).not.toContain("Tell us about your team")` |
|
||||
| auth-instruction | `expect(document.body.textContent).toContain("Sign in to Claude then come back and enter authorization code")` |
|
||||
| saved-login | `expect(document.body.textContent).not.toContain("Use saved login")` |
|
||||
|
||||
Exactly one production owner changed per control, and every owner was restored byte for byte after each mutation and checked against pinned Git bytes. Literal keeper-name filters are escaped; unselected cases are not full-suite evidence. The initial first-install receipt verifier mistook emit( for it( and rejected its receipt despite the intended test failure. The declaration-boundary matcher was corrected and that control rerun; the rejected verifier attempt supplies no accepted evidence.
|
||||
|
||||
[Controls JSON](2026-10-12-test-audit-r7-ui-onboarding-controls.json) preserves source/owner hashes, exact before/after migrations, matched setup and variable-binding proof, complete-file run/log digests, intended assertion failures and restoration checks. Temporary raw scripts/logs are identified by digests rather than committed in full.
|
||||
|
||||
The earlier broad local `pnpm test:run` was intentionally stopped before completion and is not claimed as passed. These separate focused packets precede delivery-head replay and full CI. This packet includes no push, rebase, PR or merge.
|
||||
@@ -0,0 +1,303 @@
|
||||
{
|
||||
"audit": {
|
||||
"file": "ui/src/components/RouteErrorBoundary.test.tsx",
|
||||
"base": "c39262305b6b48a5decd564af8369083cd972b33",
|
||||
"originalSha256": "aeca8c1302ed36fa9885d60b684b48fa67adc3f1a062e7b962be6a076bd93f57",
|
||||
"candidateSha256": "d4af25551dd6e7b20ffbd34500bf41603f6797187836ca7f554b898594266760",
|
||||
"allOtherProgramAstUnchanged": true,
|
||||
"allOtherSourceBytesUnchanged": true,
|
||||
"additionalDeclaredCleanup": "Remove duplicate original title assertion; identical migrated title guard remains before route change",
|
||||
"newHelpers": 0,
|
||||
"registeredInvocationsRemoved": 2,
|
||||
"rootRendersRemoved": 2,
|
||||
"netTestLinesRemoved": 31,
|
||||
"migrations": [
|
||||
{
|
||||
"retired": "reports one captured error and keeps the recovery button",
|
||||
"keeper": "recovers and renders children again after the route changes",
|
||||
"setupAstEqual": true,
|
||||
"setupBindingNormalization": null,
|
||||
"guards": [
|
||||
"expect(captureBrowserExceptionMock).toHaveBeenCalledTimes(1);",
|
||||
"expect(captureBrowserExceptionMock).toHaveBeenCalledWith(expect.any(Error), {\n boundary: \"route\", componentStack: expect.stringContaining(\"Boom\"),\n });",
|
||||
"expect(\n Array.from(container.querySelectorAll(\"button\")).some(\n (button) => button.textContent === \"Go back\",\n ),\n ).toBe(true);"
|
||||
],
|
||||
"registeredInvocationsRemoved": 1
|
||||
},
|
||||
{
|
||||
"retired": "renders a recoverable error card instead of a blank page when a child throws",
|
||||
"keeper": "recovers and renders children again after the route changes",
|
||||
"setupAstEqual": true,
|
||||
"setupBindingNormalization": null,
|
||||
"guards": [
|
||||
"expect(container.textContent).toContain(\"This page hit an error\");",
|
||||
"expect(container.textContent).toContain(\"Maximum update depth exceeded\");",
|
||||
"expect(container.querySelector(\"pre\")).not.toBeNull();"
|
||||
],
|
||||
"registeredInvocationsRemoved": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"verifierSha256": "0f1b173c8a399bb8c3e831edac6805634304a749faffcfff7b8b1900da3d34a3",
|
||||
"mutationVerifierSha256": "a05f5ba9071c0ce7ce8eac1bc0f6c7dd83401c4e720816389d779f8919312064",
|
||||
"runs": [
|
||||
{
|
||||
"kind": "baseline",
|
||||
"jsonSha256": "3782d05a0257e11e6618261f4f64121e86f253077e44c3191a3cf26b0f79cf24",
|
||||
"logSha256": "dd5e7a343956d6f41c5b87a19073a0377a0a1e45ada33495ccf0eb25b1e926bb",
|
||||
"total": 4,
|
||||
"passed": 4,
|
||||
"failed": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
{
|
||||
"kind": "candidate",
|
||||
"jsonSha256": "d6f68de33e64d9b11586f8fd885bacffe13659d1bd03d85e4b9e8fcd3e41e07e",
|
||||
"logSha256": "c39520330407b89424c964598c0580454bbb24d5fb1568570547b027be8ba082",
|
||||
"total": 2,
|
||||
"passed": 2,
|
||||
"failed": 0,
|
||||
"skipped": 0
|
||||
}
|
||||
],
|
||||
"mutations": [
|
||||
{
|
||||
"slug": "capture-count",
|
||||
"owner": "ui/src/components/RouteErrorBoundary.tsx",
|
||||
"sourceSha256": "cc0e78de2ea683aca27e1497c1aee355bb4ab9e22918f1282730be1ba78c3394",
|
||||
"title": "recovers and renders children again after the route changes",
|
||||
"mutation": {
|
||||
"before": " captureBrowserException(error, { boundary: \"route\", componentStack: info.componentStack });",
|
||||
"after": " captureBrowserException(error, { boundary: \"route\", componentStack: info.componentStack });\n captureBrowserException(error, { boundary: \"route\", componentStack: info.componentStack });",
|
||||
"replacementCount": 1,
|
||||
"additionalPreClosingTagReplacement": false
|
||||
},
|
||||
"intendedGuard": "expect(captureBrowserExceptionMock).toHaveBeenCalledTimes(1)",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "8498654db6ea2733f761cef25c488c06ae35a9fdb32341915e5614beb9ee7077",
|
||||
"logSha256": "4040e9d53955f1d919fd7932dc8a411cde138a58cb27b07a02a9cd286cbaf504",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "23a988b53557b6aa392f8f110fa672f9c34faf8480776c49a66dc4a642fc1143",
|
||||
"logSha256": "abc91cb18b2edd6a6524b4fb006a50b36b76c40d6d5960480b18d283e958648c",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected \"vi.fn()\" to be called 1 times, but got 2 times\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/RouteErrorBoundary.test.tsx:80:41\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:1628:35\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:26\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3321:20\n at new Promise (<anonymous>)\n at runWithCancel (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3316:10)\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3301:20\n at new Promise (<anonymous>)\n at runWithTimeout (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3259:10)\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3882:64"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "capture-boundary",
|
||||
"owner": "ui/src/components/RouteErrorBoundary.tsx",
|
||||
"sourceSha256": "cc0e78de2ea683aca27e1497c1aee355bb4ab9e22918f1282730be1ba78c3394",
|
||||
"title": "recovers and renders children again after the route changes",
|
||||
"mutation": {
|
||||
"before": "boundary: \"route\", componentStack: info.componentStack",
|
||||
"after": "boundary: \"app\", componentStack: info.componentStack",
|
||||
"replacementCount": 1,
|
||||
"additionalPreClosingTagReplacement": false
|
||||
},
|
||||
"intendedGuard": "expect(captureBrowserExceptionMock).toHaveBeenCalledWith(",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "aca0b48e03ef4f1562c8f41ab3bd1a036ae095e80b5abe9e10d4cb4b31cc5ce4",
|
||||
"logSha256": "1983371a3c61ad944417f51bcd350a31e9e931be5a2796a0deea63cb222998f8",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "af6c302e83aad78e4fde8ea2968ac74d31a9604002046a3fef82505c0515a8c4",
|
||||
"logSha256": "8621424418d7a4f7ba3cb039a554be9e914e73fac1989bf28aa7dbc959ace28a",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected \"vi.fn()\" to be called with arguments: [ Any<Error>, \u2026(1) ]\n\nReceived:\n\n 1st vi.fn() call:\n\n [\n- Any<Error>,\n+ Error {\n+ \"message\": \"Maximum update depth exceeded\",\n+ },\n {\n- \"boundary\": \"route\",\n- \"componentStack\": StringContaining \"Boom\",\n+ \"boundary\": \"app\",\n+ \"componentStack\": \"\n+ at Boom (/Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/RouteErrorBoundary.test.tsx:25:8)\n+ at RouteErrorBoundaryInner (/Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/RouteErrorBoundary.tsx:14:1)\n+ at RouteErrorBoundary (/Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/RouteErrorBoundary.tsx:103:31)\",\n },\n ]\n\n\nNumber of calls: 1\n\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:2233:10)\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:1944:14)\n at Proxy.methodWrapper (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/chai@6.3.0/node_modules/chai/index.js:1737:25)\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/RouteErrorBoundary.test.tsx:81:41\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:1628:35\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:26\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3321:20\n at new Promise (<anonymous>)\n at runWithCancel (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3316:10)\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3301:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "capture-stack",
|
||||
"owner": "ui/src/components/RouteErrorBoundary.tsx",
|
||||
"sourceSha256": "cc0e78de2ea683aca27e1497c1aee355bb4ab9e22918f1282730be1ba78c3394",
|
||||
"title": "recovers and renders children again after the route changes",
|
||||
"mutation": {
|
||||
"before": "boundary: \"route\", componentStack: info.componentStack",
|
||||
"after": "boundary: \"route\", componentStack: \"wrong-stack\"",
|
||||
"replacementCount": 1,
|
||||
"additionalPreClosingTagReplacement": false
|
||||
},
|
||||
"intendedGuard": "expect(captureBrowserExceptionMock).toHaveBeenCalledWith(",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "a3300f805575e44bf1080d21d4a5e340e8da1e6bee8e1b9f99b4afb2f2c5da23",
|
||||
"logSha256": "6142d202f3913c5768e0d391bf0f15cd1e3ead938d8ca6e003406110594b8365",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "3c03030c7ee7515ed74b20612ba4b1438cc211dda8d2d8ea8809213eee29f596",
|
||||
"logSha256": "1ab3c58e2732f4a56023fcaae9f286d6de2bb60ea52973c975e53a7f60bd9e92",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected \"vi.fn()\" to be called with arguments: [ Any<Error>, \u2026(1) ]\n\nReceived:\n\n 1st vi.fn() call:\n\n [\n- Any<Error>,\n+ Error {\n+ \"message\": \"Maximum update depth exceeded\",\n+ },\n {\n \"boundary\": \"route\",\n- \"componentStack\": StringContaining \"Boom\",\n+ \"componentStack\": \"wrong-stack\",\n },\n ]\n\n\nNumber of calls: 1\n\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:2233:10)\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:1944:14)\n at Proxy.methodWrapper (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/chai@6.3.0/node_modules/chai/index.js:1737:25)\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/RouteErrorBoundary.test.tsx:81:41\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:1628:35\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:26\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3321:20\n at new Promise (<anonymous>)\n at runWithCancel (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3316:10)\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3301:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "go-back",
|
||||
"owner": "ui/src/components/RouteErrorBoundary.tsx",
|
||||
"sourceSha256": "cc0e78de2ea683aca27e1497c1aee355bb4ab9e22918f1282730be1ba78c3394",
|
||||
"title": "recovers and renders children again after the route changes",
|
||||
"mutation": {
|
||||
"before": " Go back",
|
||||
"after": " Return",
|
||||
"replacementCount": 1,
|
||||
"additionalPreClosingTagReplacement": false
|
||||
},
|
||||
"intendedGuard": ").toBe(true);",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "cc46916e4056b5eda7134325b3167d1a9ad9826ba6e465ad3d3f431c0db810c6",
|
||||
"logSha256": "117b4d3c72c850183d3ab9628940f7a729dce79f55e0a777ef5927d9da441b1b",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "4b561764a1a9d962fda0610d0794f71320c0a3523642ae8ff0e49f2a3524f2b0",
|
||||
"logSha256": "116d2d94a692a6a86a8acc74dd3b2aaa3d72443b6e87274164e0cf2ad6d200b5",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected false to be true // Object.is equality\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/RouteErrorBoundary.test.tsx:88:7\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:1628:35\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:26\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3321:20\n at new Promise (<anonymous>)\n at runWithCancel (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3316:10)\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3301:20\n at new Promise (<anonymous>)\n at runWithTimeout (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3259:10)\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3882:64"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "title",
|
||||
"owner": "ui/src/components/RouteErrorBoundary.tsx",
|
||||
"sourceSha256": "cc0e78de2ea683aca27e1497c1aee355bb4ab9e22918f1282730be1ba78c3394",
|
||||
"title": "recovers and renders children again after the route changes",
|
||||
"mutation": {
|
||||
"before": "This page hit an error",
|
||||
"after": "Unexpected title",
|
||||
"replacementCount": 1,
|
||||
"additionalPreClosingTagReplacement": false
|
||||
},
|
||||
"intendedGuard": "expect(container.textContent).toContain(\"This page hit an error\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "f4f6f6cd80fd8ea6a668520c5e678cca1af4f2af117beed5c27aaedccd6a3888",
|
||||
"logSha256": "5f4ba767c3a107c3dbba86fc9959045a2d7d989c1a03a6f566eff3fc3130faa4",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "ee00df253bff2477b681d9c817ad323faf1d2e4b7f10fde13a1fe49f90530b65",
|
||||
"logSha256": "7ec386fd0c0fd4f37a8ac6bf5f7ad37f217f9be4a4647618750e92a937dac05e",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected 'Unexpected titleSomething went wrong \u2026' to contain 'This page hit an error'\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/RouteErrorBoundary.test.tsx:90:35\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:1628:35\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:26\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3321:20\n at new Promise (<anonymous>)\n at runWithCancel (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3316:10)\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3301:20\n at new Promise (<anonymous>)\n at runWithTimeout (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3259:10)\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3882:64"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "detail",
|
||||
"owner": "ui/src/components/RouteErrorBoundary.tsx",
|
||||
"sourceSha256": "cc0e78de2ea683aca27e1497c1aee355bb4ab9e22918f1282730be1ba78c3394",
|
||||
"title": "recovers and renders children again after the route changes",
|
||||
"mutation": {
|
||||
"before": "{error.message}",
|
||||
"after": "{\"hidden detail\"}",
|
||||
"replacementCount": 1,
|
||||
"additionalPreClosingTagReplacement": false
|
||||
},
|
||||
"intendedGuard": "expect(container.textContent).toContain(\"Maximum update depth exceeded\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "cb7f79721a1f5f3a32b1d9ca0749875d97ad9b644e2663d84226ce12edd9124a",
|
||||
"logSha256": "b0ed753166122eafbd441172e5a2b47460fb08a2987cbacd53edb81861d33fd3",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "123f7949c426028edc343688cc50548d03399d5d56d5bb4a5dfcc7e5f7ed0ea9",
|
||||
"logSha256": "0f9c80ef5e76823ced425f4f7e11cd9adce0c776eebd99170564b2bd4bb035c7",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected 'This page hit an errorSomething went \u2026' to contain 'Maximum update depth exceeded'\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/RouteErrorBoundary.test.tsx:91:35\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:1628:35\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:26\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3321:20\n at new Promise (<anonymous>)\n at runWithCancel (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3316:10)\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3301:20\n at new Promise (<anonymous>)\n at runWithTimeout (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3259:10)\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3882:64"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "pre",
|
||||
"owner": "ui/src/components/RouteErrorBoundary.tsx",
|
||||
"sourceSha256": "cc0e78de2ea683aca27e1497c1aee355bb4ab9e22918f1282730be1ba78c3394",
|
||||
"title": "recovers and renders children again after the route changes",
|
||||
"mutation": {
|
||||
"before": "<pre className=",
|
||||
"after": "<div className=",
|
||||
"replacementCount": 1,
|
||||
"additionalPreClosingTagReplacement": true
|
||||
},
|
||||
"intendedGuard": "expect(container.querySelector(\"pre\")).not.toBeNull()",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "21c50a1cc9340c311c63b5c2a030cc6345004e0a5a610be679b7ed3a7d1506d8",
|
||||
"logSha256": "d5be38cd7bd1f352f64d188d53c777f5eb7d18e9c3e11d9a43ee90a1809b72cb",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "44a7f4f7e9783b4e653d0db1512e2c40cc1d22502987517c18a36fd60152873e",
|
||||
"logSha256": "8d8849edac3006c90066a8e877ef863570e42f9cfe862f2a99e3d9b79ac829a1",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected null not to be null\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/RouteErrorBoundary.test.tsx:92:48\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:1628:35\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:26\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3321:20\n at new Promise (<anonymous>)\n at runWithCancel (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3316:10)\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3301:20\n at new Promise (<anonymous>)\n at runWithTimeout (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3259:10)\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3882:64"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"priorEvidenceUnchanged": [
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appdetail-controls.json",
|
||||
"sha256": "7906fde0d62e14a7511b5cf45f864c9386a4c377922333eefc7f7e703c832f6a"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appdetail.md",
|
||||
"sha256": "715f23cd27502c92d0f5d1b83b91bcac03f254c73ab63b44181ae76939805229"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-controls.json",
|
||||
"sha256": "0d445f6f066032f2d9cd724525a8d7d2290246cbfeee1f6ab4b44818467af2a7"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-transcript-controls.json",
|
||||
"sha256": "9e4dbdc33806d6fcc912dc3aacc8691a77939e2ce2403032b2a8127c0e407e94"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-transcript.md",
|
||||
"sha256": "9e4ac8c92a3a9eca727c29a77ae428702d19ecdee0cab0e3dfcda0a36bf004db"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui.md",
|
||||
"sha256": "896b9928af85a4c7d588dfca93484980aadb238bd79d8142e671c62f0b191fa8"
|
||||
}
|
||||
],
|
||||
"ownerRestoredToBaseGitBytes": true,
|
||||
"productionLinesChanged": 0,
|
||||
"postControlPolish": {
|
||||
"controlCandidateSha256": "7d0c20e033b7f3daeccb0731ae544f213fccbfb297386786af014fdf385d5b93",
|
||||
"polishedCandidateSha256": "d4af25551dd6e7b20ffbd34500bf41603f6797187836ca7f554b898594266760",
|
||||
"difference": "Remove duplicate original title assertion; identical migrated title guard remains before route change",
|
||||
"allIntendedGuardStatementsAndLocationsUnchanged": true,
|
||||
"completePolishedFileReplayPassed": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
# Test audit, Round 7 UI — Route error boundary follow-up
|
||||
|
||||
This isolated follow-up removes **2 registered executions, 2 root renders and 31 net test lines** from `ui/src/components/RouteErrorBoundary.test.tsx`. It changes no production lines and adds no helper. The pinned audit base is `c39262305b6b48a5decd564af8369083cd972b33`. Prior UI proof remains unchanged. Registration/render reductions are per complete-suite invocation; no measured runtime or CI-speed claim is made.
|
||||
|
||||
## Exact migrations
|
||||
|
||||
| Retired registration | Keeper | Original observations retained |
|
||||
|---|---|---|
|
||||
| `reports one captured error and keeps the recovery button` | `recovers and renders children again after the route changes` | expect(captureBrowserExceptionMock).toHaveBeenCalledTimes(1);; expect(captureBrowserExceptionMock).toHaveBeenCalledWith(expect.any(Error), { boundary: "route", componentStack: expect.stringContaining("Boom"), });; expect( Array.from(container.querySelectorAll("button")).some( (button) => button.textContent === "Go back", ), ).toBe(true); |
|
||||
| `renders a recoverable error card instead of a blank page when a child throws` | `recovers and renders children again after the route changes` | expect(container.textContent).toContain("This page hit an error");; expect(container.textContent).toContain("Maximum update depth exceeded");; expect(container.querySelector("pre")).not.toBeNull(); |
|
||||
|
||||
Layout.tsx and Layout.production.tsx wrap the routed Outlet with RouteErrorBoundary. Its inner boundary captures the thrown error and component stack, renders recovery UI and resets after pathname/search changes. Paired initial createRoot/Boom/act subtrees and unmount statements are AST-identical. All migrated guards run before route mutation and retain the original capture metadata, count, Go-back presence, title, detail and pre checks. The duplicate original title assertion is removed after proving equality with the migrated title guard; the separate actual Go-back click/navigation test remains unchanged.
|
||||
|
||||
The verifier reconstructs the exact candidate text from only the declared removals and insertions, requires byte equality, and compares the entire program AST after the same migrations. Every unrelated source byte, hook, mock, test body and binding remains unchanged, outside the audit receipt’s explicitly declared duplicate-title or blank-line cleanup where applicable. Setup ASTs are equal except the explicitly normalized attachment callback binding described above where applicable. No tests are skipped, softened, suppressed or added. Each file remains included in `@paperclipai/ui` under CI `general-workspaces-a`; Vitest file sharding selects it once across the two shards, with no workflow/config change.
|
||||
|
||||
## Complete-file evidence
|
||||
|
||||
| Run | Registered | Passed | Failed | Skipped |
|
||||
|---|---:|---:|---:|---:|
|
||||
| Baseline | 4 | 4 | 0 | 0 |
|
||||
| Candidate | 2 | 2 | 0 | 0 |
|
||||
|
||||
From `ui/`: `pnpm exec vitest run src/components/RouteErrorBoundary.test.tsx`.
|
||||
|
||||
All 7 separately selected positive keeper controls passed. Every deliberate behavior mutation failed at the corresponding intended keeper assertion, not setup, timeout or another guard:
|
||||
|
||||
| Mutation | Intended assertion |
|
||||
|---|---|
|
||||
| capture-count | `expect(captureBrowserExceptionMock).toHaveBeenCalledTimes(1)` |
|
||||
| capture-boundary | `expect(captureBrowserExceptionMock).toHaveBeenCalledWith(` |
|
||||
| capture-stack | `expect(captureBrowserExceptionMock).toHaveBeenCalledWith(` |
|
||||
| go-back | `).toBe(true);` |
|
||||
| title | `expect(container.textContent).toContain("This page hit an error")` |
|
||||
| detail | `expect(container.textContent).toContain("Maximum update depth exceeded")` |
|
||||
| pre | `expect(container.querySelector("pre")).not.toBeNull()` |
|
||||
|
||||
Every mutated production owner was restored byte for byte after each mutation and checked against pinned Git bytes. Name-filtered controls select exactly one keeper; their unselected tests are not full-suite evidence. [Compact controls](2026-10-12-test-audit-r7-ui-route-controls.json) preserve source/owner hashes, exact migration map, body verifier digests, complete run/log digests, intended failure receipts and restoration checks. Temporary AST/receipt scripts initially needed corrections for chained assertions or statement position; those verifier attempts produced no accepted test evidence.
|
||||
|
||||
The earlier broad local `pnpm test:run` was intentionally stopped before completion; it is not claimed as a pass. These focused runs do not substitute for pending delivery-head CI. No push, rebase, pull request or merge is included in this packet.
|
||||
|
||||
The mutation controls preceded the final duplicate original-title removal. Exact byte reconstruction confirms that every intended migrated guard and its source location stayed unchanged; the final polished complete file passed again. The controls JSON records both candidate hashes.
|
||||
@@ -0,0 +1,192 @@
|
||||
{
|
||||
"audit": {
|
||||
"file": "ui/src/components/environment-variables-editor/EnvironmentVariablesEditor.test.tsx",
|
||||
"base": "2e76f5157240ee8b2d42adbdcd4c345aea07c013",
|
||||
"originalSha256": "23857fdf6e5db9d28c63f37ce24f0fd86b5eb57645d4b69ee7c01c77dfef7c04",
|
||||
"candidateSha256": "07201fa2e9521bf6e235ee954ec4f7d72e9381d0083667130a9c5a907c7b1e41",
|
||||
"allOtherProgramAstUnchanged": true,
|
||||
"allOtherSourceBytesUnchanged": true,
|
||||
"newHelpers": 0,
|
||||
"registeredInvocationsRemoved": 1,
|
||||
"renderInvocationsRemoved": 1,
|
||||
"setupInvocationsRemoved": 1,
|
||||
"netTestLinesRemoved": 25,
|
||||
"migrations": [
|
||||
{
|
||||
"retired": "opens the create-secret popover from the picker's + Create item (\u00a76.4, PAP-12476)",
|
||||
"keeper": "keeps the create-secret popover open when focus returns to a control inside the value cell (\u00a76.4, PAP-12492)",
|
||||
"exactLeadingStatements": 9,
|
||||
"sameEnclosingHooks": true,
|
||||
"explicitCleanupAstEqual": false,
|
||||
"kind": "normal",
|
||||
"exactMigratedStatements": [
|
||||
"expect(\n document.querySelector('input[aria-label=\"Secret name\"]'),\n \"create-secret name field should render\",\n ).toBeTruthy();"
|
||||
],
|
||||
"alreadyExactKeeperStatementsOrBindings": [],
|
||||
"registeredInvocationsRemoved": 1,
|
||||
"renderInvocationsRemoved": 1,
|
||||
"setupInvocationsRemoved": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"verifierSha256": "ff07f5e2e308cfc0f26584a6cd6599bcd98665e79d7f4782ed5bb36b35cb8cb9",
|
||||
"mutationVerifierSha256": "676b973d4838ed130c5ae92d4bc50fb32a65309af8c858450ec34bcce13729e9",
|
||||
"runs": [
|
||||
{
|
||||
"kind": "baseline",
|
||||
"total": 28,
|
||||
"passed": 28,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"jsonSha256": "353ef0936ad65121e272049737cae95e8c3afcabaf78d7abb68fae773ab8af6f",
|
||||
"logSha256": "d5113caa5264644daf864032f6842fa4bfc514b3877e74d7d7d2d6fd11421c48"
|
||||
},
|
||||
{
|
||||
"kind": "candidate",
|
||||
"total": 27,
|
||||
"passed": 27,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"jsonSha256": "139fedbdb9bfb03c4d5d9595a4249b12ecb948d731f96e02f0962b0321cdea37",
|
||||
"logSha256": "436156bfece2588699e879311e69a2a015701682a3786573df2aff1c29df5fa9"
|
||||
}
|
||||
],
|
||||
"mutations": [
|
||||
{
|
||||
"slug": "initial-secret-name",
|
||||
"owner": "ui/src/components/environment-variables-editor/CreateSecretPopover.tsx",
|
||||
"sourceSha256": "d971769d01a99a53aff654e6b837b9e2502eb0f8f05b9f4474e8a5b23d46f535",
|
||||
"title": "keeps the create-secret popover open when focus returns to a control inside the value cell (\u00a76.4, PAP-12492)",
|
||||
"mutation": {
|
||||
"before": "aria-label=\"Secret name\"",
|
||||
"after": "aria-label=\"Missing secret name\"",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "document.querySelector('input[aria-label=\"Secret name\"]')",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "c83e93ae3f862d9ba20f93d3e7174f9736d5ce00fa7c8e64bf49a7f0721aaddc",
|
||||
"logSha256": "d5ac329ef6d3cca724475b72d44c5db38ffdf6633a5f31a7151352389b3fab9c",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "c8944aa987dc601cec48de263d03c4fdf44e5da061bb55d21880c4590fee6d97",
|
||||
"logSha256": "7bcf8061f31e3d87a657e33bc2436ae72933b0236ab6ae7d5adfe552da2630f7",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: create-secret name field should render: expected null to be truthy\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/environment-variables-editor/EnvironmentVariablesEditor.test.tsx:700:7\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"priorEvidenceUnchanged": [
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-agentconfig-controls.json",
|
||||
"sha256": "cfb4357610beaa464cdb26848f74a7b8d967d6409c63dbd6821c92886a9cf980"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-agentconfig.md",
|
||||
"sha256": "ea6d5dfc8cedcd653edd55ca9d77568431413a351f4de5db77ca6ac8f22b051a"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appboundary-controls.json",
|
||||
"sha256": "bad49e7bc92dea919df6b980bfa45e7452984cf31a6fd4655b355ba0444ff9a6"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appboundary.md",
|
||||
"sha256": "cd6f173584db0d485004af6f85b1ce78fa65b19d8c6ef582b061f0d232c6c1ed"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appdetail-controls.json",
|
||||
"sha256": "7906fde0d62e14a7511b5cf45f864c9386a4c377922333eefc7f7e703c832f6a"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appdetail.md",
|
||||
"sha256": "715f23cd27502c92d0f5d1b83b91bcac03f254c73ab63b44181ae76939805229"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-attachments-controls.json",
|
||||
"sha256": "c4ff66a3226e1edafd286cad0ca45c9445795b46944cf70d606c59a754913f3a"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-attachments.md",
|
||||
"sha256": "d38715393c95306d10e871a5a2c9a32f105fa1452871cd7ad030d86dbbdb7416"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-controls.json",
|
||||
"sha256": "0d445f6f066032f2d9cd724525a8d7d2290246cbfeee1f6ab4b44818467af2a7"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-experimental-controls.json",
|
||||
"sha256": "9c72abee7ee1a937fdbd6ccee870320308bc7ce06b4fc1e338cd9bd3b0efba6b"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-experimental.md",
|
||||
"sha256": "93b7583a8ebba39dc97e390918fd62029955a00beda22756f55bd6374acc3737"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-inline-controls.json",
|
||||
"sha256": "af9d3f115e6e0518c2c0a2e11b8913e7aa82a35c848f114e6750884323601e17"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-inline.md",
|
||||
"sha256": "52d8e27970bd1c091ae7edf403b2331e921081da9198270df65ff779a8efc1bc"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-issuechat-controls.json",
|
||||
"sha256": "45d86fa901c8ab40bc3fe98d266e3ba1a7bbc93edb7bc2aae60ccd9bfa130c37"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-issuechat.md",
|
||||
"sha256": "15e84a553c5a468aea013941f68d3aa517bfb5a13ae296a90e1a39586f85de8e"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-issuedetail-controls.json",
|
||||
"sha256": "a56f183f1c6b940662db0c4bfb62457eda0cec453c2019b439ec716ed9d2a3e1"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-issuedetail.md",
|
||||
"sha256": "e137af5b991c936a167d6ad6f3c710b99688e939f839b163b203259fc998ded8"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-route-controls.json",
|
||||
"sha256": "0a72a7770ec749f2c0507a74d395e65d70b722d0b9d2a767a2c066a67ed46382"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-route.md",
|
||||
"sha256": "9b5e1543163d6c9d0958aa3e377a593ec458f6674ce1ddb2bf3ca158786f09c4"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-sidebar-controls.json",
|
||||
"sha256": "ae9f24746e67432cf6247c5da130b9c1bba46fc85112c0610d3f18545dfce326"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-sidebar.md",
|
||||
"sha256": "5e267441c43aa8375fa5c54edcbd2879428d657708be9a2ab372aa66e4792886"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-timeline-controls.json",
|
||||
"sha256": "6a86b07770f1cd8d758334fb61c46254197a7f533d24c056fc9a52c317488291"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-timeline.md",
|
||||
"sha256": "612dc3ec4c3d435888055ba20a7f28230ce89ea8b071b8c38d1ea2c147074a96"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-transcript-controls.json",
|
||||
"sha256": "9e4dbdc33806d6fcc912dc3aacc8691a77939e2ce2403032b2a8127c0e407e94"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-transcript.md",
|
||||
"sha256": "9e4ac8c92a3a9eca727c29a77ae428702d19ecdee0cab0e3dfcda0a36bf004db"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui.md",
|
||||
"sha256": "896b9928af85a4c7d588dfca93484980aadb238bd79d8142e671c62f0b191fa8"
|
||||
}
|
||||
],
|
||||
"ownerRestoredToBaseGitBytes": true,
|
||||
"productionLinesChanged": 0
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
# Test audit, Round 7 UI — Secret picker popover follow-up
|
||||
|
||||
This separate packet removes **1 registered executions, 1 rendered scenarios and 25 net test lines** from `ui/src/components/environment-variables-editor/EnvironmentVariablesEditor.test.tsx`. It adds no helper and changes no production lines. Audit base: `2e76f5157240ee8b2d42adbdcd4c345aea07c013`. All prior committed proof remains byte-identical. Registration/render savings are per complete-suite invocation; no measured runtime or CI-speed claim is made. A service-worker retirement counts only initializer setup, never a render.
|
||||
|
||||
## Exact retirement map
|
||||
|
||||
| Retired registration | Keeper | Exact observations migrated |
|
||||
|---|---|---|
|
||||
| `opens the create-secret popover from the picker's + Create item (§6.4, PAP-12476)` | `keeps the create-secret popover open when focus returns to a control inside the value cell (§6.4, PAP-12492)` | expect( document.querySelector('input[aria-label="Secret name"]'), "create-secret name field should render", ).toBeTruthy(); |
|
||||
|
||||
The retired picker/create transition and keeper use the same secret-ref value, secrets fixture, fresh callbacks, editor render, combobox focus, Create-item lookup/click and flush. Nine leading statements already match, including the initial heading assertion. The exact initial Secret name input-presence check moves before the keeper drives its late in-anchor focus return. Row.tsx retains the outside-focus guard; CreateSecretPopover.tsx owns the actual name input. Later heading/input persistence checks, outside interactions, store-as-secret and secret lifecycle cases remain unchanged.
|
||||
|
||||
The verifier requires matching setup statements, enclosing hooks and explicit teardown where present. It reconstructs candidate source solely from the declared registrations/assertion migrations and requires exact byte equality plus full-program AST equality outside those edits. Existing shared variable bindings, mock arguments and provider/component inputs remain the same. No other fixture, helper, action order, wait, assertion strength, timer or cleanup changes. Default CI includes the file in `@paperclipai/ui` under `general-workspaces-a`, once across its two file shards, with no workflow/config change.
|
||||
|
||||
## Complete owner-file results
|
||||
|
||||
| Run | Registered | Passed | Failed | Skipped |
|
||||
|---|---:|---:|---:|---:|
|
||||
| Baseline | 28 | 28 | 0 | 0 |
|
||||
| Candidate | 27 | 27 | 0 | 0 |
|
||||
|
||||
From `ui/`: `pnpm exec vitest run src/components/environment-variables-editor/EnvironmentVariablesEditor.test.tsx`.
|
||||
|
||||
All 1 separately selected positive controls passed. All 1 distinct production-owner regressions failed at intended retained/migrated assertions, not setup, timeout or another guard:
|
||||
|
||||
| Regression | Intended guard |
|
||||
|---|---|
|
||||
| initial-secret-name | `document.querySelector('input[aria-label="Secret name"]')` |
|
||||
|
||||
Exactly one production owner changed per control, and every owner was restored byte for byte after each mutation and checked against pinned Git bytes. Literal keeper-name filters are escaped; unselected cases are not full-suite evidence. The initial first-install receipt verifier mistook emit( for it( and rejected its receipt despite the intended test failure. The declaration-boundary matcher was corrected and that control rerun; the rejected verifier attempt supplies no accepted evidence.
|
||||
|
||||
[Controls JSON](2026-10-12-test-audit-r7-ui-secret-popover-controls.json) preserves source/owner hashes, exact before/after migrations, matched setup and variable-binding proof, complete-file run/log digests, intended assertion failures and restoration checks. Temporary raw scripts/logs are identified by digests rather than committed in full.
|
||||
|
||||
The earlier broad local `pnpm test:run` was intentionally stopped before completion and is not claimed as passed. These separate focused packets precede delivery-head replay and full CI. This packet includes no push, rebase, PR or merge.
|
||||
@@ -0,0 +1,197 @@
|
||||
{
|
||||
"audit": {
|
||||
"file": "ui/src/lib/service-worker-updates.test.ts",
|
||||
"base": "2e76f5157240ee8b2d42adbdcd4c345aea07c013",
|
||||
"originalSha256": "536e1fd2e7c9c0641fa45a9c4b3a5a2d08819e6673c599cf25dc2c26403b19f2",
|
||||
"candidateSha256": "225c31546a4bedc53651e364723ef24865c7b0bdb8e73e4f4f201d9c9f39bf51",
|
||||
"allOtherProgramAstUnchanged": true,
|
||||
"allOtherSourceBytesUnchanged": true,
|
||||
"newHelpers": 0,
|
||||
"registeredInvocationsRemoved": 1,
|
||||
"renderInvocationsRemoved": 0,
|
||||
"setupInvocationsRemoved": 1,
|
||||
"netTestLinesRemoved": 10,
|
||||
"migrations": [
|
||||
{
|
||||
"retired": "does not reload on a first-ever install",
|
||||
"keeper": "reloads when a later deploy replaces the worker a first-visit tab installed",
|
||||
"exactLeadingStatements": 6,
|
||||
"sameEnclosingHooks": true,
|
||||
"explicitCleanupAstEqual": false,
|
||||
"kind": "subset",
|
||||
"exactMigratedStatements": [],
|
||||
"alreadyExactKeeperStatementsOrBindings": [
|
||||
"const { container, emit } = fakeContainer({ controlled: false });",
|
||||
"const { doc } = fakeDocument(\"hidden\");",
|
||||
"const reload = vi.fn();",
|
||||
"startServiceWorkerUpdates({ container, documentRef: doc, reload });",
|
||||
"emit(\"controllerchange\");",
|
||||
"expect(reload).not.toHaveBeenCalled();"
|
||||
],
|
||||
"registeredInvocationsRemoved": 1,
|
||||
"renderInvocationsRemoved": 0,
|
||||
"setupInvocationsRemoved": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"verifierSha256": "ff07f5e2e308cfc0f26584a6cd6599bcd98665e79d7f4782ed5bb36b35cb8cb9",
|
||||
"mutationVerifierSha256": "676b973d4838ed130c5ae92d4bc50fb32a65309af8c858450ec34bcce13729e9",
|
||||
"runs": [
|
||||
{
|
||||
"kind": "baseline",
|
||||
"total": 9,
|
||||
"passed": 9,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"jsonSha256": "3b7fd48a3efcfb1e5cb4316e9a4bd1337765ad83f241269c30ad98407877a2bc",
|
||||
"logSha256": "17439460b27c125513f7429f55f7a702a1b4e8643b9be25f30758a49aae64ccc"
|
||||
},
|
||||
{
|
||||
"kind": "candidate",
|
||||
"total": 8,
|
||||
"passed": 8,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"jsonSha256": "a64d06c0f236e73f3e446a515111f74c99f2f924ac381a6f8d4b88767b7cfba2",
|
||||
"logSha256": "855085927b57d14b77892447f94ba3bc875946aa11e0208f900a4e481f7e51c7"
|
||||
}
|
||||
],
|
||||
"mutations": [
|
||||
{
|
||||
"slug": "first-install",
|
||||
"owner": "ui/src/lib/service-worker-updates.ts",
|
||||
"sourceSha256": "2a6334bf805d331093ab9970d638cb732f0bb8070ef1ae2abea422ef8ce872db",
|
||||
"title": "reloads when a later deploy replaces the worker a first-visit tab installed",
|
||||
"mutation": {
|
||||
"before": "let wasControlled = Boolean(container.controller);",
|
||||
"after": "let wasControlled = true;",
|
||||
"replacementCount": 1
|
||||
},
|
||||
"intendedGuard": "expect(reload).not.toHaveBeenCalled()",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "a3511733ddddee2fa1b578225f0ec4e24544c824f76035e91c7a09517744f2a2",
|
||||
"logSha256": "0598496c0b9388dc737b62b28f24a48e5242f3b78dc2871a6809be676215569a",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "421853ba449e7c93190f57187b683e42cc281f6ce5e744f5f786e8ec36425699",
|
||||
"logSha256": "b8326ed6cb42630f0418ed7f75c8a43e88ee52de81b48c0315252ced142b166e",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected \"vi.fn()\" to not be called at all, but actually been called 1 times\n\nReceived:\n\n 1st vi.fn() call:\n\n Array []\n\n\nNumber of calls: 1\n\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:2214:51)\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:1944:14)\n at Proxy.methodWrapper (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/chai@6.3.0/node_modules/chai/index.js:1737:25)\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/lib/service-worker-updates.test.ts:97:24\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:1628:35\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:26\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3321:20\n at new Promise (<anonymous>)\n at runWithCancel (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3316:10)\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:3301:20"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"priorEvidenceUnchanged": [
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-agentconfig-controls.json",
|
||||
"sha256": "cfb4357610beaa464cdb26848f74a7b8d967d6409c63dbd6821c92886a9cf980"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-agentconfig.md",
|
||||
"sha256": "ea6d5dfc8cedcd653edd55ca9d77568431413a351f4de5db77ca6ac8f22b051a"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appboundary-controls.json",
|
||||
"sha256": "bad49e7bc92dea919df6b980bfa45e7452984cf31a6fd4655b355ba0444ff9a6"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appboundary.md",
|
||||
"sha256": "cd6f173584db0d485004af6f85b1ce78fa65b19d8c6ef582b061f0d232c6c1ed"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appdetail-controls.json",
|
||||
"sha256": "7906fde0d62e14a7511b5cf45f864c9386a4c377922333eefc7f7e703c832f6a"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appdetail.md",
|
||||
"sha256": "715f23cd27502c92d0f5d1b83b91bcac03f254c73ab63b44181ae76939805229"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-attachments-controls.json",
|
||||
"sha256": "c4ff66a3226e1edafd286cad0ca45c9445795b46944cf70d606c59a754913f3a"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-attachments.md",
|
||||
"sha256": "d38715393c95306d10e871a5a2c9a32f105fa1452871cd7ad030d86dbbdb7416"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-controls.json",
|
||||
"sha256": "0d445f6f066032f2d9cd724525a8d7d2290246cbfeee1f6ab4b44818467af2a7"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-experimental-controls.json",
|
||||
"sha256": "9c72abee7ee1a937fdbd6ccee870320308bc7ce06b4fc1e338cd9bd3b0efba6b"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-experimental.md",
|
||||
"sha256": "93b7583a8ebba39dc97e390918fd62029955a00beda22756f55bd6374acc3737"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-inline-controls.json",
|
||||
"sha256": "af9d3f115e6e0518c2c0a2e11b8913e7aa82a35c848f114e6750884323601e17"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-inline.md",
|
||||
"sha256": "52d8e27970bd1c091ae7edf403b2331e921081da9198270df65ff779a8efc1bc"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-issuechat-controls.json",
|
||||
"sha256": "45d86fa901c8ab40bc3fe98d266e3ba1a7bbc93edb7bc2aae60ccd9bfa130c37"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-issuechat.md",
|
||||
"sha256": "15e84a553c5a468aea013941f68d3aa517bfb5a13ae296a90e1a39586f85de8e"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-issuedetail-controls.json",
|
||||
"sha256": "a56f183f1c6b940662db0c4bfb62457eda0cec453c2019b439ec716ed9d2a3e1"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-issuedetail.md",
|
||||
"sha256": "e137af5b991c936a167d6ad6f3c710b99688e939f839b163b203259fc998ded8"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-route-controls.json",
|
||||
"sha256": "0a72a7770ec749f2c0507a74d395e65d70b722d0b9d2a767a2c066a67ed46382"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-route.md",
|
||||
"sha256": "9b5e1543163d6c9d0958aa3e377a593ec458f6674ce1ddb2bf3ca158786f09c4"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-sidebar-controls.json",
|
||||
"sha256": "ae9f24746e67432cf6247c5da130b9c1bba46fc85112c0610d3f18545dfce326"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-sidebar.md",
|
||||
"sha256": "5e267441c43aa8375fa5c54edcbd2879428d657708be9a2ab372aa66e4792886"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-timeline-controls.json",
|
||||
"sha256": "6a86b07770f1cd8d758334fb61c46254197a7f533d24c056fc9a52c317488291"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-timeline.md",
|
||||
"sha256": "612dc3ec4c3d435888055ba20a7f28230ce89ea8b071b8c38d1ea2c147074a96"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-transcript-controls.json",
|
||||
"sha256": "9e4dbdc33806d6fcc912dc3aacc8691a77939e2ce2403032b2a8127c0e407e94"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-transcript.md",
|
||||
"sha256": "9e4ac8c92a3a9eca727c29a77ae428702d19ecdee0cab0e3dfcda0a36bf004db"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui.md",
|
||||
"sha256": "896b9928af85a4c7d588dfca93484980aadb238bd79d8142e671c62f0b191fa8"
|
||||
}
|
||||
],
|
||||
"ownerRestoredToBaseGitBytes": true,
|
||||
"productionLinesChanged": 0
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
# Test audit, Round 7 UI — First service-worker takeover follow-up
|
||||
|
||||
This separate packet removes **1 registered executions, 0 rendered scenarios and 10 net test lines** from `ui/src/lib/service-worker-updates.test.ts`. It adds no helper and changes no production lines. Audit base: `2e76f5157240ee8b2d42adbdcd4c345aea07c013`. All prior committed proof remains byte-identical. Registration/render savings are per complete-suite invocation; no measured runtime or CI-speed claim is made. A service-worker retirement counts only initializer setup, never a render.
|
||||
|
||||
## Exact retirement map
|
||||
|
||||
| Retired registration | Keeper | Exact observations migrated |
|
||||
|---|---|---|
|
||||
| `does not reload on a first-ever install` | `reloads when a later deploy replaces the worker a first-visit tab installed` | |
|
||||
|
||||
The retired complete body is an exact prefix of the keeper: fresh uncontrolled fake container, hidden document, reload mock, real startServiceWorkerUpdates invocation, first controllerchange and no-reload assertion. The keeper remains byte-identical, then verifies that the later takeover reloads exactly once. This retirement removes one registration and initializer/observer setup, not a render. Initial-controlled and uncontrolled states, visibility, update checks and cleanup cases stay distinct. The mutation incorrectly treats a first-visit tab as already controlled; the retained first no-reload guard fails, so the boundary remains clear and meaningful.
|
||||
|
||||
The verifier requires matching setup statements, enclosing hooks and explicit teardown where present. It reconstructs candidate source solely from the declared registrations/assertion migrations and requires exact byte equality plus full-program AST equality outside those edits. Existing shared variable bindings, mock arguments and provider/component inputs remain the same. No other fixture, helper, action order, wait, assertion strength, timer or cleanup changes. Default CI includes the file in `@paperclipai/ui` under `general-workspaces-a`, once across its two file shards, with no workflow/config change.
|
||||
|
||||
## Complete owner-file results
|
||||
|
||||
| Run | Registered | Passed | Failed | Skipped |
|
||||
|---|---:|---:|---:|---:|
|
||||
| Baseline | 9 | 9 | 0 | 0 |
|
||||
| Candidate | 8 | 8 | 0 | 0 |
|
||||
|
||||
From `ui/`: `pnpm exec vitest run src/lib/service-worker-updates.test.ts`.
|
||||
|
||||
All 1 separately selected positive controls passed. All 1 distinct production-owner regressions failed at intended retained/migrated assertions, not setup, timeout or another guard:
|
||||
|
||||
| Regression | Intended guard |
|
||||
|---|---|
|
||||
| first-install | `expect(reload).not.toHaveBeenCalled()` |
|
||||
|
||||
Exactly one production owner changed per control, and every owner was restored byte for byte after each mutation and checked against pinned Git bytes. Literal keeper-name filters are escaped; unselected cases are not full-suite evidence. The initial first-install receipt verifier mistook emit( for it( and rejected its receipt despite the intended test failure. The declaration-boundary matcher was corrected and that control rerun; the rejected verifier attempt supplies no accepted evidence.
|
||||
|
||||
[Controls JSON](2026-10-12-test-audit-r7-ui-service-worker-controls.json) preserves source/owner hashes, exact before/after migrations, matched setup and variable-binding proof, complete-file run/log digests, intended assertion failures and restoration checks. Temporary raw scripts/logs are identified by digests rather than committed in full.
|
||||
|
||||
The earlier broad local `pnpm test:run` was intentionally stopped before completion and is not claimed as passed. These separate focused packets precede delivery-head replay and full CI. This packet includes no push, rebase, PR or merge.
|
||||
@@ -0,0 +1,244 @@
|
||||
{
|
||||
"audit": {
|
||||
"file": "ui/src/components/Sidebar.test.tsx",
|
||||
"base": "c39262305b6b48a5decd564af8369083cd972b33",
|
||||
"originalSha256": "9b463dd219ff0c4ef3a76f853feb29514e740102cf8f838a6bef981682d43f78",
|
||||
"candidateSha256": "5b9033240feffd2c58165893f7c8a3037982711826415da8a52f330a05000eba",
|
||||
"allOtherProgramAstUnchanged": true,
|
||||
"allOtherSourceBytesUnchanged": true,
|
||||
"registeredInvocationsRemoved": 4,
|
||||
"providerRootRendersRemoved": 4,
|
||||
"newHelpers": 0,
|
||||
"netTestLinesRemoved": 40,
|
||||
"migrations": [
|
||||
{
|
||||
"retired": "does not flash the Workspaces link while experimental settings are loading",
|
||||
"keeper": "keeps the simplified navigation while experimental settings are loading",
|
||||
"setupAstEqual": true,
|
||||
"unmountAstEqual": true,
|
||||
"guards": [
|
||||
"expect(container.textContent).not.toContain(\"Workspaces\");"
|
||||
],
|
||||
"registeredInvocationsRemoved": 1
|
||||
},
|
||||
{
|
||||
"retired": "reserves the Goals nav slot while experimental settings are loading",
|
||||
"keeper": "keeps the simplified navigation while experimental settings are loading",
|
||||
"setupAstEqual": true,
|
||||
"unmountAstEqual": true,
|
||||
"guards": [
|
||||
"expect([...container.querySelectorAll(\"nav a\")].map((a) => a.textContent?.trim())).not.toContain(\"Goals\");",
|
||||
"expect(container.querySelector('[data-testid=\"sidebar-goals-placeholder\"]')).not.toBeNull();"
|
||||
],
|
||||
"registeredInvocationsRemoved": 1
|
||||
},
|
||||
{
|
||||
"retired": "does not flash the Conference Room item while experimental settings are loading (PAP-137)",
|
||||
"keeper": "keeps the simplified navigation while experimental settings are loading",
|
||||
"setupAstEqual": true,
|
||||
"unmountAstEqual": true,
|
||||
"guards": [
|
||||
"expect(container.textContent).not.toContain(\"Conference Room\");"
|
||||
],
|
||||
"registeredInvocationsRemoved": 1
|
||||
},
|
||||
{
|
||||
"retired": "does not flash the Pipelines nav item while experimental settings are loading",
|
||||
"keeper": "keeps the simplified navigation while experimental settings are loading",
|
||||
"setupAstEqual": true,
|
||||
"unmountAstEqual": true,
|
||||
"guards": [
|
||||
"expect(container.textContent).not.toContain(\"Pipelines\");"
|
||||
],
|
||||
"registeredInvocationsRemoved": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"verifierSha256": "31de795f5ffc44365740f1788b497fe117c236778ce05d0a95cc2472c014ce71",
|
||||
"mutationVerifierSha256": "3783a894b558341f2a8ef0eddf7f774fb6ee46833161feca5def1279d7d4b887",
|
||||
"runs": [
|
||||
{
|
||||
"kind": "baseline",
|
||||
"jsonSha256": "38374087c2e9c98935c9b0e6e563c827127b21750f9797d3536271591bf793a5",
|
||||
"logSha256": "361d260b375e5252086dac55605788a1a54421715d38ddc00700442562e707eb",
|
||||
"total": 35,
|
||||
"passed": 35,
|
||||
"failed": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
{
|
||||
"kind": "candidate",
|
||||
"jsonSha256": "ce7c9e0fd848df8baf87a6d60c00190fae11eacbdd01991ca0e22388a1205780",
|
||||
"logSha256": "a7bc412cee1de9d731c66a69dac53e69fa195807951091fefd1298c9b120ef86",
|
||||
"total": 31,
|
||||
"passed": 31,
|
||||
"failed": 0,
|
||||
"skipped": 0
|
||||
}
|
||||
],
|
||||
"mutations": [
|
||||
{
|
||||
"slug": "workspaces",
|
||||
"owner": "ui/src/components/Sidebar.tsx",
|
||||
"sourceSha256": "2baa44740b00babc7fc5a02c2d28d8b5ed2bc478ad8840200f2689f073a1c9bd",
|
||||
"title": "keeps the simplified navigation while experimental settings are loading",
|
||||
"mutation": {
|
||||
"before": "const showWorkspacesLink = !chatRail && experimentalSettings?.enableIsolatedWorkspaces === true;",
|
||||
"after": "const showWorkspacesLink = experimentalSettings === undefined || (!chatRail && experimentalSettings?.enableIsolatedWorkspaces === true);"
|
||||
},
|
||||
"intendedGuard": "expect(container.textContent).not.toContain(\"Workspaces\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "0925c954fb40aeadf79dea76a015a9dcb637e2db9995b62e05094c86e0343f51",
|
||||
"logSha256": "04c617da040c5b2f26885b6268951335b4c048f4deeed0fc2ec5ee511992b23a",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "adb925244eaeb8a6b3206f425c5e10775ec7f3cda791a965e739c55264cb4626",
|
||||
"logSha256": "6cf3b4b626a80e4443325c75f7fe1887f12425322f142d93b69c476fcda9e8f3",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected 'Company menuNew TaskSearchDashboardIn\u2026' not to contain 'Workspaces'\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/Sidebar.test.tsx:270:39\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "goals",
|
||||
"owner": "ui/src/components/Sidebar.tsx",
|
||||
"sourceSha256": "2baa44740b00babc7fc5a02c2d28d8b5ed2bc478ad8840200f2689f073a1c9bd",
|
||||
"title": "keeps the simplified navigation while experimental settings are loading",
|
||||
"mutation": {
|
||||
"before": "const showGoalsLink = experimentalSettings?.enableGoalsSidebarLink === true;",
|
||||
"after": "const showGoalsLink = experimentalSettings === undefined || experimentalSettings?.enableGoalsSidebarLink === true;"
|
||||
},
|
||||
"intendedGuard": "expect([...container.querySelectorAll(\"nav a\")].map((a) => a.textContent?.trim())).not.toContain(\"Goals\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "c65540e311c4131bb3b367088e8b3a2d175eb55577bcd434dd0128b4169374e9",
|
||||
"logSha256": "87f3efaff20b56dfe4943004415205e0f1e1d06733230ccf8cd9dc27162cbebb",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "512f85c2e3ec85a0c09364a4872484e237f3771a7628911b569602b8987a98eb",
|
||||
"logSha256": "d58f1e168ce951a214c10f9b2a690b061fc98113b3645ce1504129606a247620",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected [ 'Search', 'Dashboard', \u2026(10) ] to not include 'Goals'\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:2077:15)\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:1944:14)\n at Proxy.methodWrapper (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/chai@6.3.0/node_modules/chai/index.js:1737:25)\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/Sidebar.test.tsx:271:92\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "conference",
|
||||
"owner": "ui/src/components/Sidebar.tsx",
|
||||
"sourceSha256": "2baa44740b00babc7fc5a02c2d28d8b5ed2bc478ad8840200f2689f073a1c9bd",
|
||||
"title": "keeps the simplified navigation while experimental settings are loading",
|
||||
"mutation": {
|
||||
"before": "const conferenceRoomChatEnabled = experimentalSettings?.enableConferenceRoomChat === true;",
|
||||
"after": "const conferenceRoomChatEnabled = experimentalSettings === undefined || experimentalSettings?.enableConferenceRoomChat === true;"
|
||||
},
|
||||
"intendedGuard": "expect(container.textContent).not.toContain(\"Conference Room\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "0637b1e10ca0d6d18e82baf74113b71d5217c879f7c26ce16fc2aab888c942ec",
|
||||
"logSha256": "88ba4df5eab5e9e6b90f43104c534d9ec4cdfeb32770a1d66a301c47dd9381d5",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "0867024b3b2a6995608c8eefaafe9bc4d59000dee742c987d6d3948e89352ddd",
|
||||
"logSha256": "c03a4143999fc21ff93cd6e945113cb76c140c34483515a26f4321eb84b25d24",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected 'Company menuNew TaskSearchDashboardIn\u2026' not to contain 'Conference Room'\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/Sidebar.test.tsx:273:39\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "pipelines",
|
||||
"owner": "ui/src/components/Sidebar.tsx",
|
||||
"sourceSha256": "2baa44740b00babc7fc5a02c2d28d8b5ed2bc478ad8840200f2689f073a1c9bd",
|
||||
"title": "keeps the simplified navigation while experimental settings are loading",
|
||||
"mutation": {
|
||||
"before": "const showPipelines = experimentalSettings?.enablePipelines === true;",
|
||||
"after": "const showPipelines = experimentalSettings === undefined || experimentalSettings?.enablePipelines === true;"
|
||||
},
|
||||
"intendedGuard": "expect(container.textContent).not.toContain(\"Pipelines\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "290be9d7e8547a1842c594f0ba83c443e812ebaf7cebbb5ecf1a17f155d07cbc",
|
||||
"logSha256": "5d56516d7a59c85d3c4926780e6ec3c1b60467fcd9818160cc0014da29adb6c5",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "5922637d763e6dbe8091839eef6f6d1336c22c32caaf922671058471fb8834ee",
|
||||
"logSha256": "bf37d6a6eddb8da880fd0fff2680369b11cd9784d81d0f1d36fc7129ea3be981",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected 'Company menuNew TaskSearchDashboardIn\u2026' not to contain 'Pipelines'\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/Sidebar.test.tsx:274:39\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "goals-placeholder",
|
||||
"owner": "ui/src/components/Sidebar.tsx",
|
||||
"sourceSha256": "2baa44740b00babc7fc5a02c2d28d8b5ed2bc478ad8840200f2689f073a1c9bd",
|
||||
"title": "keeps the simplified navigation while experimental settings are loading",
|
||||
"mutation": {
|
||||
"before": "const goalsLinkPending = experimentalSettings === undefined;",
|
||||
"after": "const goalsLinkPending = false;"
|
||||
},
|
||||
"intendedGuard": "expect(container.querySelector('[data-testid=\"sidebar-goals-placeholder\"]')).not.toBeNull()",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "db75c234ed61cab71950d8e371a17496f3faa6e378f8fb4c8f5ba2eda2ff657a",
|
||||
"logSha256": "79549245a36c31565101c45b74edbc22a9ebeffbe8b6206e3ba8530c3f03d454",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "af191c72c1f19e45e061cd3b4af054e4abe41087e48cf7b882b78f5698805621",
|
||||
"logSha256": "528addefacd70920cd7fd16fbc15cb6be237fdc21379d6e61722ee847648aa3f",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected null not to be null\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/components/Sidebar.test.tsx:272:86\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"priorEvidenceUnchanged": [
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appdetail-controls.json",
|
||||
"sha256": "7906fde0d62e14a7511b5cf45f864c9386a4c377922333eefc7f7e703c832f6a"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appdetail.md",
|
||||
"sha256": "715f23cd27502c92d0f5d1b83b91bcac03f254c73ab63b44181ae76939805229"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-controls.json",
|
||||
"sha256": "0d445f6f066032f2d9cd724525a8d7d2290246cbfeee1f6ab4b44818467af2a7"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-transcript-controls.json",
|
||||
"sha256": "9e4dbdc33806d6fcc912dc3aacc8691a77939e2ce2403032b2a8127c0e407e94"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-transcript.md",
|
||||
"sha256": "9e4ac8c92a3a9eca727c29a77ae428702d19ecdee0cab0e3dfcda0a36bf004db"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui.md",
|
||||
"sha256": "896b9928af85a4c7d588dfca93484980aadb238bd79d8142e671c62f0b191fa8"
|
||||
}
|
||||
],
|
||||
"ownerRestoredToBaseGitBytes": true,
|
||||
"productionLinesChanged": 0
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
# Test audit, Round 7 UI — Sidebar loading state follow-up
|
||||
|
||||
This isolated follow-up removes **4 registered executions, 4 root renders and 40 net test lines** from `ui/src/components/Sidebar.test.tsx`. It changes no production lines and adds no helper. The pinned audit base is `c39262305b6b48a5decd564af8369083cd972b33`. Prior UI proof remains unchanged. Registration/render reductions are per complete-suite invocation; no measured runtime or CI-speed claim is made.
|
||||
|
||||
## Exact migrations
|
||||
|
||||
| Retired registration | Keeper | Original observations retained |
|
||||
|---|---|---|
|
||||
| `does not flash the Workspaces link while experimental settings are loading` | `keeps the simplified navigation while experimental settings are loading` | expect(container.textContent).not.toContain("Workspaces"); |
|
||||
| `reserves the Goals nav slot while experimental settings are loading` | `keeps the simplified navigation while experimental settings are loading` | expect([...container.querySelectorAll("nav a")].map((a) => a.textContent?.trim())).not.toContain("Goals");; expect(container.querySelector('[data-testid="sidebar-goals-placeholder"]')).not.toBeNull(); |
|
||||
| `does not flash the Conference Room item while experimental settings are loading (PAP-137)` | `keeps the simplified navigation while experimental settings are loading` | expect(container.textContent).not.toContain("Conference Room"); |
|
||||
| `does not flash the Pipelines nav item while experimental settings are loading` | `keeps the simplified navigation while experimental settings are loading` | expect(container.textContent).not.toContain("Pipelines"); |
|
||||
|
||||
Sidebar.tsx loads instance settings through useQuery. Workspaces, Goals, Conference Room and Pipelines derive from the same unresolved experimentalSettings value; Goals preserves its pending placeholder. The keeper uses the exact original never-resolving promise and renderSidebar helper. Existing nav checks remain; all five original moved assertions run before the unchanged unmount. Enabled, disabled, mobile, legacy, chat and permission/navigation variants remain distinct.
|
||||
|
||||
The verifier reconstructs the exact candidate text from only the declared removals and insertions, requires byte equality, and compares the entire program AST after the same migrations. Every unrelated source byte, hook, mock, test body and binding remains unchanged, outside the audit receipt’s explicitly declared duplicate-title or blank-line cleanup where applicable. Setup ASTs are equal except the explicitly normalized attachment callback binding described above where applicable. No tests are skipped, softened, suppressed or added. Each file remains included in `@paperclipai/ui` under CI `general-workspaces-a`; Vitest file sharding selects it once across the two shards, with no workflow/config change.
|
||||
|
||||
## Complete-file evidence
|
||||
|
||||
| Run | Registered | Passed | Failed | Skipped |
|
||||
|---|---:|---:|---:|---:|
|
||||
| Baseline | 35 | 35 | 0 | 0 |
|
||||
| Candidate | 31 | 31 | 0 | 0 |
|
||||
|
||||
From `ui/`: `pnpm exec vitest run src/components/Sidebar.test.tsx`.
|
||||
|
||||
All 5 separately selected positive keeper controls passed. Every deliberate behavior mutation failed at the corresponding intended keeper assertion, not setup, timeout or another guard:
|
||||
|
||||
| Mutation | Intended assertion |
|
||||
|---|---|
|
||||
| workspaces | `expect(container.textContent).not.toContain("Workspaces")` |
|
||||
| goals | `expect([...container.querySelectorAll("nav a")].map((a) => a.textContent?.trim())).not.toContain("Goals")` |
|
||||
| conference | `expect(container.textContent).not.toContain("Conference Room")` |
|
||||
| pipelines | `expect(container.textContent).not.toContain("Pipelines")` |
|
||||
| goals-placeholder | `expect(container.querySelector('[data-testid="sidebar-goals-placeholder"]')).not.toBeNull()` |
|
||||
|
||||
Every mutated production owner was restored byte for byte after each mutation and checked against pinned Git bytes. Name-filtered controls select exactly one keeper; their unselected tests are not full-suite evidence. [Compact controls](2026-10-12-test-audit-r7-ui-sidebar-controls.json) preserve source/owner hashes, exact migration map, body verifier digests, complete run/log digests, intended failure receipts and restoration checks. Temporary AST/receipt scripts initially needed corrections for chained assertions or statement position; those verifier attempts produced no accepted test evidence.
|
||||
|
||||
The earlier broad local `pnpm test:run` was intentionally stopped before completion; it is not claimed as a pass. These focused runs do not substitute for pending delivery-head CI. No push, rebase, pull request or merge is included in this packet.
|
||||
@@ -0,0 +1,271 @@
|
||||
{
|
||||
"audit": {
|
||||
"file": "ui/src/pages/Timeline.test.tsx",
|
||||
"base": "c39262305b6b48a5decd564af8369083cd972b33",
|
||||
"originalSha256": "19543e8f10e41d438633bd3a825f45a9fa3c56f2807c01bc245b4e8e185a1108",
|
||||
"candidateSha256": "8d5909b8aaf4d5d882d2fd1bc9072a2e8bb7fce9c98466ca15a6382e279ec9a7",
|
||||
"allOtherProgramAstUnchanged": true,
|
||||
"allOtherSourceBytesUnchanged": true,
|
||||
"additionalDeclaredCleanup": "Remove extra blank line before describe closes",
|
||||
"newHelpers": 0,
|
||||
"registeredInvocationsRemoved": 2,
|
||||
"rootRendersRemoved": 2,
|
||||
"netTestLinesRemoved": 26,
|
||||
"migrations": [
|
||||
{
|
||||
"retired": "requests the collapsed app sidebar by default",
|
||||
"keeper": "renders range controls plus icon zoom controls without the user lens selector or visible-duration readout",
|
||||
"setupAstEqual": true,
|
||||
"setupBindingNormalization": null,
|
||||
"guards": [
|
||||
"expect(container.querySelector('[data-testid=\"request-collapsed-sidebar\"]')).not.toBeNull();"
|
||||
],
|
||||
"registeredInvocationsRemoved": 1
|
||||
},
|
||||
{
|
||||
"retired": "requests the company timeline without a user lens parameter",
|
||||
"keeper": "renders range controls plus icon zoom controls without the user lens selector or visible-duration readout",
|
||||
"setupAstEqual": true,
|
||||
"setupBindingNormalization": null,
|
||||
"guards": [
|
||||
"expect(mockWorkTimelineApi.get).toHaveBeenCalledWith(\n \"company-1\",\n expect.objectContaining({\n from: expect.any(String),\n to: expect.any(String),\n }),\n { signal: expect.any(AbortSignal) },\n );",
|
||||
"expect(mockWorkTimelineApi.get.mock.calls[0]?.[1]).not.toHaveProperty(\"userId\");"
|
||||
],
|
||||
"registeredInvocationsRemoved": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"verifierSha256": "0f1b173c8a399bb8c3e831edac6805634304a749faffcfff7b8b1900da3d34a3",
|
||||
"mutationVerifierSha256": "a05f5ba9071c0ce7ce8eac1bc0f6c7dd83401c4e720816389d779f8919312064",
|
||||
"runs": [
|
||||
{
|
||||
"kind": "baseline",
|
||||
"jsonSha256": "ae7cd09b89cd59f8f56d2ce5da5de1c87118bfd6b2893f212d61feff14398d1e",
|
||||
"logSha256": "85573e535172170fc924ed4ec78737698a3a21cebb3cc9d1aa5fdc72564c44c8",
|
||||
"total": 9,
|
||||
"passed": 9,
|
||||
"failed": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
{
|
||||
"kind": "candidate",
|
||||
"jsonSha256": "8ae0a854a756f627c20177d38418368d2ba82e141cc85a2010136af545449938",
|
||||
"logSha256": "122fdad4346b64464466e96f0f34d5169578dcdc83de673df9ea82306a51224f",
|
||||
"total": 7,
|
||||
"passed": 7,
|
||||
"failed": 0,
|
||||
"skipped": 0
|
||||
}
|
||||
],
|
||||
"mutations": [
|
||||
{
|
||||
"slug": "collapsed",
|
||||
"owner": "ui/src/pages/Timeline.tsx",
|
||||
"sourceSha256": "32dd72ff0b295bf23863f438a1be2b0262f039ea4e86b20c0e8df12abc5fb703",
|
||||
"title": "renders range controls plus icon zoom controls without the user lens selector or visible-duration readout",
|
||||
"mutation": {
|
||||
"before": "{!embedded && <RequestCollapsedSidebar />}",
|
||||
"after": "{false && !embedded && <RequestCollapsedSidebar />}",
|
||||
"replacementCount": 2,
|
||||
"additionalPreClosingTagReplacement": false
|
||||
},
|
||||
"intendedGuard": "expect(container.querySelector('[data-testid=\"request-collapsed-sidebar\"]')).not.toBeNull()",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "3c601ebb6478cc5815ab76983793956f042357ebc63a753df89d786ff5487e7d",
|
||||
"logSha256": "bc0475e992fcaddd61f32e2bc5038fc469b86a8895c33159909cb089f5f1fc1b",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "1669312785afa8b36c3e8495ff74cadddc7669a208289aa2a18687b4035cb89e",
|
||||
"logSha256": "caf49d3737ee24ea97c9f3adbf9165b8943ee107f66454c0a594ae5015afbc81",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected null not to be null\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/pages/Timeline.test.tsx:187:86\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "userId",
|
||||
"owner": "ui/src/pages/Timeline.tsx",
|
||||
"sourceSha256": "32dd72ff0b295bf23863f438a1be2b0262f039ea4e86b20c0e8df12abc5fb703",
|
||||
"title": "renders range controls plus icon zoom controls without the user lens selector or visible-duration readout",
|
||||
"mutation": {
|
||||
"before": " ...params,",
|
||||
"after": " ...params,\n userId: \"unexpected-user\",",
|
||||
"replacementCount": 1,
|
||||
"additionalPreClosingTagReplacement": false
|
||||
},
|
||||
"intendedGuard": "expect(mockWorkTimelineApi.get.mock.calls[0]?.[1]).not.toHaveProperty(\"userId\")",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "f7f10efaff0dd60e4cdcf0cc25f48382b14abc2223a8999e570444988940af60",
|
||||
"logSha256": "eb14e95f3ba6aa4ef7c296071894a3ef933c82f5d89d9624e2fba7ce6faadd5b",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "d809b1ab3cc65b66e7de8d8f09dc33f26ab2ce30c45fd7d5b1960389628cb0e8",
|
||||
"logSha256": "73d702114b4bb05f2629e7b07be87a62b0cbdfb92958c2db55a3808bb7156b6f",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected { \u2026(5) } to not have property \"userId\"\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/pages/Timeline.test.tsx:197:60\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "company",
|
||||
"owner": "ui/src/pages/Timeline.tsx",
|
||||
"sourceSha256": "32dd72ff0b295bf23863f438a1be2b0262f039ea4e86b20c0e8df12abc5fb703",
|
||||
"title": "renders range controls plus icon zoom controls without the user lens selector or visible-duration readout",
|
||||
"mutation": {
|
||||
"before": "workTimelineApi.get(companyId, {",
|
||||
"after": "workTimelineApi.get(\"wrong-company\", {",
|
||||
"replacementCount": 1,
|
||||
"additionalPreClosingTagReplacement": false
|
||||
},
|
||||
"intendedGuard": "expect(mockWorkTimelineApi.get).toHaveBeenCalledWith(",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "cd568cc81271b304b2fc0c977a746436f7e6b49ebbc5e2f662fc9edfd20d517e",
|
||||
"logSha256": "b0e17b15d6b5feeeabfa130ef7450242c7903631ee3ad90c15c348bea3924e8b",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "5336632844af286db208fdf555dd21685ab4e6cc22ac09f26ad3550379d24bc0",
|
||||
"logSha256": "340421b7b504bd8d0676f36fc2761f33a1a492e3e93dc3fb2bd8b5e183d13546",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected \"vi.fn()\" to be called with arguments: [ 'company-1', \u2026(2) ]\n\nReceived:\n\n 1st vi.fn() call:\n\n [\n- \"company-1\",\n- ObjectContaining {\n- \"from\": Any<String>,\n- \"to\": Any<String>,\n+ \"wrong-company\",\n+ {\n+ \"from\": \"2026-10-06T05:00:00.000Z\",\n+ \"limit\": 500,\n+ \"offset\": 0,\n+ \"to\": \"2026-10-13T04:59:59.999Z\",\n },\n {\n- \"signal\": Any<AbortSignal>,\n+ \"signal\": AbortSignal {\n+ Symbol(kEvents): Map {},\n+ Symbol(events.maxEventTargetListeners): 0,\n+ Symbol(events.maxEventTargetListenersWarned): false,\n+ Symbol(kHandlers): Map {},\n+ Symbol(kAborted): false,\n+ Symbol(kReason): undefined,\n+ Symbol(kComposite): false,\n+ },\n },\n ]\n\n\nNumber of calls: 1\n\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:2233:10)\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:1944:14)\n at Proxy.methodWrapper (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/chai@6.3.0/node_modules/chai/index.js:1737:25)\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/pages/Timeline.test.tsx:189:37\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "from",
|
||||
"owner": "ui/src/pages/Timeline.tsx",
|
||||
"sourceSha256": "32dd72ff0b295bf23863f438a1be2b0262f039ea4e86b20c0e8df12abc5fb703",
|
||||
"title": "renders range controls plus icon zoom controls without the user lens selector or visible-duration readout",
|
||||
"mutation": {
|
||||
"before": " ...params,",
|
||||
"after": " ...params,\n from: 123,",
|
||||
"replacementCount": 1,
|
||||
"additionalPreClosingTagReplacement": false
|
||||
},
|
||||
"intendedGuard": "expect(mockWorkTimelineApi.get).toHaveBeenCalledWith(",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "0aa7e25d872ce8864151a25adf4ed3d744b425e99273a24a55edf55f6ab1b6ba",
|
||||
"logSha256": "aaf0f2657f7bb1ca04517ce053e0728fb83c94223664d4ef1fb0cae0f9d61cd5",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "9feb2d30523ad4e7567d61d28e24f69eaa1a1869eaf1ff6e01cdb829d5c50b15",
|
||||
"logSha256": "dd4740f663a636023f5ced054eaed3e51b0d1ee3db5df51f8f0127c8329564a6",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected \"vi.fn()\" to be called with arguments: [ 'company-1', \u2026(2) ]\n\nReceived:\n\n 1st vi.fn() call:\n\n [\n \"company-1\",\n- ObjectContaining {\n- \"from\": Any<String>,\n- \"to\": Any<String>,\n+ {\n+ \"from\": 123,\n+ \"limit\": 500,\n+ \"offset\": 0,\n+ \"to\": \"2026-10-13T04:59:59.999Z\",\n },\n {\n- \"signal\": Any<AbortSignal>,\n+ \"signal\": AbortSignal {\n+ Symbol(kEvents): Map {},\n+ Symbol(events.maxEventTargetListeners): 0,\n+ Symbol(events.maxEventTargetListenersWarned): false,\n+ Symbol(kHandlers): Map {},\n+ Symbol(kAborted): false,\n+ Symbol(kReason): undefined,\n+ Symbol(kComposite): false,\n+ },\n },\n ]\n\n\nNumber of calls: 1\n\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:2233:10)\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:1944:14)\n at Proxy.methodWrapper (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/chai@6.3.0/node_modules/chai/index.js:1737:25)\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/pages/Timeline.test.tsx:189:37\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "to",
|
||||
"owner": "ui/src/pages/Timeline.tsx",
|
||||
"sourceSha256": "32dd72ff0b295bf23863f438a1be2b0262f039ea4e86b20c0e8df12abc5fb703",
|
||||
"title": "renders range controls plus icon zoom controls without the user lens selector or visible-duration readout",
|
||||
"mutation": {
|
||||
"before": " ...params,",
|
||||
"after": " ...params,\n to: 123,",
|
||||
"replacementCount": 1,
|
||||
"additionalPreClosingTagReplacement": false
|
||||
},
|
||||
"intendedGuard": "expect(mockWorkTimelineApi.get).toHaveBeenCalledWith(",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "21260048ec34af7eda86634ddd81d75077b8e8cbaa7b8fd54406a59de8ac2d7c",
|
||||
"logSha256": "3100577ba46ffe7b80de31995086231d60745954b26e5e95cab0462b7925f4bf",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "8c49b367f7089b044ea8084ec2c03f7896402544b0d1f917601d941b000c4355",
|
||||
"logSha256": "e00c810574b08bb023ddb25751e81a0320b013ea8bd6b9a25f4b56406a246ccb",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected \"vi.fn()\" to be called with arguments: [ 'company-1', \u2026(2) ]\n\nReceived:\n\n 1st vi.fn() call:\n\n [\n \"company-1\",\n- ObjectContaining {\n- \"from\": Any<String>,\n- \"to\": Any<String>,\n+ {\n+ \"from\": \"2026-10-06T05:00:00.000Z\",\n+ \"limit\": 500,\n+ \"offset\": 0,\n+ \"to\": 123,\n },\n {\n- \"signal\": Any<AbortSignal>,\n+ \"signal\": AbortSignal {\n+ Symbol(kEvents): Map {},\n+ Symbol(events.maxEventTargetListeners): 0,\n+ Symbol(events.maxEventTargetListenersWarned): false,\n+ Symbol(kHandlers): Map {},\n+ Symbol(kAborted): false,\n+ Symbol(kReason): undefined,\n+ Symbol(kComposite): false,\n+ },\n },\n ]\n\n\nNumber of calls: 1\n\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:2233:10)\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:1944:14)\n at Proxy.methodWrapper (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/chai@6.3.0/node_modules/chai/index.js:1737:25)\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/pages/Timeline.test.tsx:189:37\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "signal",
|
||||
"owner": "ui/src/pages/Timeline.tsx",
|
||||
"sourceSha256": "32dd72ff0b295bf23863f438a1be2b0262f039ea4e86b20c0e8df12abc5fb703",
|
||||
"title": "renders range controls plus icon zoom controls without the user lens selector or visible-duration readout",
|
||||
"mutation": {
|
||||
"before": " }, { signal });",
|
||||
"after": " }, { signal: undefined });",
|
||||
"replacementCount": 1,
|
||||
"additionalPreClosingTagReplacement": false
|
||||
},
|
||||
"intendedGuard": "expect(mockWorkTimelineApi.get).toHaveBeenCalledWith(",
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"jsonSha256": "f7137b440fa63b4b7dfcaa7d733a6836389ff6a3385d768021dcd9cd4a600961",
|
||||
"logSha256": "74011dd8441e744c01a605d359e1f714fef60505e180f010bd7a364962ff038b",
|
||||
"caseStatus": "passed"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"jsonSha256": "e52b536a50fd6fd1dfa8aeb0a71411e67277be3003911be7e592a3d70657c7c7",
|
||||
"logSha256": "e8be8243f0804bb96128cc9b62c55658309267c156cf0bc238081d317f1f3eb5",
|
||||
"caseStatus": "failed",
|
||||
"intendedFailureMessages": [
|
||||
"AssertionError: expected \"vi.fn()\" to be called with arguments: [ 'company-1', \u2026(2) ]\n\nReceived:\n\n 1st vi.fn() call:\n\n [\n \"company-1\",\n- ObjectContaining {\n- \"from\": Any<String>,\n- \"to\": Any<String>,\n+ {\n+ \"from\": \"2026-10-06T05:00:00.000Z\",\n+ \"limit\": 500,\n+ \"offset\": 0,\n+ \"to\": \"2026-10-13T04:59:59.999Z\",\n },\n {\n- \"signal\": Any<AbortSignal>,\n+ \"signal\": undefined,\n },\n ]\n\n\nNumber of calls: 1\n\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:2233:10)\n at Proxy.<anonymous> (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/index.C4tKZ0yW.js:1944:14)\n at Proxy.methodWrapper (file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/chai@6.3.0/node_modules/chai/index.js:1737:25)\n at /Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/ui/src/pages/Timeline.test.tsx:189:37\n at file:///Users/dotta/.codex/worktrees/test-audit-r7-ui/paperclip/node_modules/.pnpm/vitest@5.0.3_@opentelemetry+api@1.9.1_@types+node@24.13.3_jsdom@30.0.1_@noble+hashes@2.4.0__v_wr5mxfuu6kgge6st623q4v5egm/node_modules/vitest/dist/chunks/run.BTlFXlnv.js:2783:20"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"priorEvidenceUnchanged": [
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appdetail-controls.json",
|
||||
"sha256": "7906fde0d62e14a7511b5cf45f864c9386a4c377922333eefc7f7e703c832f6a"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-appdetail.md",
|
||||
"sha256": "715f23cd27502c92d0f5d1b83b91bcac03f254c73ab63b44181ae76939805229"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-controls.json",
|
||||
"sha256": "0d445f6f066032f2d9cd724525a8d7d2290246cbfeee1f6ab4b44818467af2a7"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-transcript-controls.json",
|
||||
"sha256": "9e4dbdc33806d6fcc912dc3aacc8691a77939e2ce2403032b2a8127c0e407e94"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui-transcript.md",
|
||||
"sha256": "9e4ac8c92a3a9eca727c29a77ae428702d19ecdee0cab0e3dfcda0a36bf004db"
|
||||
},
|
||||
{
|
||||
"file": "doc/plans/2026-10-12-test-audit-r7-ui.md",
|
||||
"sha256": "896b9928af85a4c7d588dfca93484980aadb238bd79d8142e671c62f0b191fa8"
|
||||
}
|
||||
],
|
||||
"ownerRestoredToBaseGitBytes": true,
|
||||
"productionLinesChanged": 0,
|
||||
"postControlPolish": {
|
||||
"controlCandidateSha256": "e5f6171e4fa9998e4bf14edad445701c5ae003f401875e7fcf278546e3f9cdf7",
|
||||
"polishedCandidateSha256": "8d5909b8aaf4d5d882d2fd1bc9072a2e8bb7fce9c98466ca15a6382e279ec9a7",
|
||||
"difference": "Remove extra blank line before describe closes",
|
||||
"allIntendedGuardStatementsAndLocationsUnchanged": true,
|
||||
"completePolishedFileReplayPassed": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
# Test audit, Round 7 UI — Timeline default render follow-up
|
||||
|
||||
This isolated follow-up removes **2 registered executions, 2 root renders and 26 net test lines** from `ui/src/pages/Timeline.test.tsx`. It changes no production lines and adds no helper. The pinned audit base is `c39262305b6b48a5decd564af8369083cd972b33`. Prior UI proof remains unchanged. Registration/render reductions are per complete-suite invocation; no measured runtime or CI-speed claim is made.
|
||||
|
||||
## Exact migrations
|
||||
|
||||
| Retired registration | Keeper | Original observations retained |
|
||||
|---|---|---|
|
||||
| `requests the collapsed app sidebar by default` | `renders range controls plus icon zoom controls without the user lens selector or visible-duration readout` | expect(container.querySelector('[data-testid="request-collapsed-sidebar"]')).not.toBeNull(); |
|
||||
| `requests the company timeline without a user lens parameter` | `renders range controls plus icon zoom controls without the user lens selector or visible-duration readout` | expect(mockWorkTimelineApi.get).toHaveBeenCalledWith( "company-1", expect.objectContaining({ from: expect.any(String), to: expect.any(String), }), { signal: expect.any(AbortSignal) }, );; expect(mockWorkTimelineApi.get.mock.calls[0]?.[1]).not.toHaveProperty("userId"); |
|
||||
|
||||
Timeline.tsx calls loadTimelineWindow with the selected company, computed date window and AbortSignal. The default unembedded render requests RequestCollapsedSidebar. All three paired cases use the same emptyTimeline beforeEach result, company context, blank URL search, fresh query client, render and flush. Sidebar-request and complete API argument/no-userId guards move after existing controls assertions. Populated stats, pagination, clipping, overlap and project scope remain distinct.
|
||||
|
||||
The verifier reconstructs the exact candidate text from only the declared removals and insertions, requires byte equality, and compares the entire program AST after the same migrations. Every unrelated source byte, hook, mock, test body and binding remains unchanged, outside the audit receipt’s explicitly declared duplicate-title or blank-line cleanup where applicable. Setup ASTs are equal except the explicitly normalized attachment callback binding described above where applicable. No tests are skipped, softened, suppressed or added. Each file remains included in `@paperclipai/ui` under CI `general-workspaces-a`; Vitest file sharding selects it once across the two shards, with no workflow/config change.
|
||||
|
||||
## Complete-file evidence
|
||||
|
||||
| Run | Registered | Passed | Failed | Skipped |
|
||||
|---|---:|---:|---:|---:|
|
||||
| Baseline | 9 | 9 | 0 | 0 |
|
||||
| Candidate | 7 | 7 | 0 | 0 |
|
||||
|
||||
From `ui/`: `pnpm exec vitest run src/pages/Timeline.test.tsx`.
|
||||
|
||||
All 6 separately selected positive keeper controls passed. Every deliberate behavior mutation failed at the corresponding intended keeper assertion, not setup, timeout or another guard:
|
||||
|
||||
| Mutation | Intended assertion |
|
||||
|---|---|
|
||||
| collapsed | `expect(container.querySelector('[data-testid="request-collapsed-sidebar"]')).not.toBeNull()` |
|
||||
| userId | `expect(mockWorkTimelineApi.get.mock.calls[0]?.[1]).not.toHaveProperty("userId")` |
|
||||
| company | `expect(mockWorkTimelineApi.get).toHaveBeenCalledWith(` |
|
||||
| from | `expect(mockWorkTimelineApi.get).toHaveBeenCalledWith(` |
|
||||
| to | `expect(mockWorkTimelineApi.get).toHaveBeenCalledWith(` |
|
||||
| signal | `expect(mockWorkTimelineApi.get).toHaveBeenCalledWith(` |
|
||||
|
||||
Every mutated production owner was restored byte for byte after each mutation and checked against pinned Git bytes. Name-filtered controls select exactly one keeper; their unselected tests are not full-suite evidence. [Compact controls](2026-10-12-test-audit-r7-ui-timeline-controls.json) preserve source/owner hashes, exact migration map, body verifier digests, complete run/log digests, intended failure receipts and restoration checks. Temporary AST/receipt scripts initially needed corrections for chained assertions or statement position; those verifier attempts produced no accepted test evidence.
|
||||
|
||||
The earlier broad local `pnpm test:run` was intentionally stopped before completion; it is not claimed as a pass. These focused runs do not substitute for pending delivery-head CI. No push, rebase, pull request or merge is included in this packet.
|
||||
|
||||
The mutation controls preceded the final blank-line cleanup. Exact byte reconstruction confirms that every intended migrated guard and its source location stayed unchanged; the final polished complete file passed again. The controls JSON records both candidate hashes.
|
||||
@@ -0,0 +1,139 @@
|
||||
{
|
||||
"audit": {
|
||||
"file": "ui/src/components/task-chat/transcript-adapter.test.ts",
|
||||
"base": "51dc1eb69f5c52d6ef0e29cd2e4061da6c88871f",
|
||||
"originalSha256": "a4b107fd4a12ee5acf55ee2a6aabcf1f8d7f26202b8adf2c533d1929a39be1ef",
|
||||
"candidateSha256": "f79f72eb7d5f43e26fb0ac9f614887786dabea6f82af12e64446aba5fa54e03c",
|
||||
"allOtherProgramAstUnchanged": true,
|
||||
"allOtherSourceBytesUnchanged": true,
|
||||
"formattingOnlyCleanup": "Remove one extra blank line before the enclosing describe closes",
|
||||
"newHelpers": 0,
|
||||
"registeredInvocationsRemoved": 2,
|
||||
"parserCallsRemoved": 2,
|
||||
"netTestLinesRemoved": 15,
|
||||
"migrations": [
|
||||
{
|
||||
"retired": "marks only the message still open at the tail as streaming",
|
||||
"keeper": "tags agent messages streamed inside a live run turn as interstitial",
|
||||
"parserInputsAndFilterEqual": true,
|
||||
"originalKindGuardRetained": true,
|
||||
"exactMigratedStatements": [
|
||||
"if (messages[0].kind !== \"message\" || messages[1].kind !== \"message\")\n return;",
|
||||
"expect(messages[0].streaming).toBe(false);",
|
||||
"expect(messages[1].streaming).toBe(true);"
|
||||
],
|
||||
"registeredInvocationsRemoved": 1,
|
||||
"parserCallsRemoved": 1
|
||||
},
|
||||
{
|
||||
"retired": "stamps atMs from the first streamed chunk",
|
||||
"keeper": "tags settled-history messages interstitial too, so live and history agree",
|
||||
"parserInputsAndFilterEqual": true,
|
||||
"originalKindGuardRetained": true,
|
||||
"exactMigratedStatements": [
|
||||
"if (messages[0].kind !== \"message\" || messages[1].kind !== \"message\")\n return;",
|
||||
"expect(messages[0].atMs).toBe(Date.parse(TS));",
|
||||
"expect(messages[1].atMs).toBe(Date.parse(\"2026-07-31T12:00:05.000Z\"));"
|
||||
],
|
||||
"registeredInvocationsRemoved": 1,
|
||||
"parserCallsRemoved": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"verifierSha256": "421f9dbbf4e63e1ed307279704a1be2918526bc35109fa15adc88d06668d0c58",
|
||||
"runs": [
|
||||
{
|
||||
"kind": "baseline",
|
||||
"jsonSha256": "2bc04c1382a274652a867e74fd7916721419e325e76c4c364757538a85d35300",
|
||||
"total": 105,
|
||||
"passed": 105,
|
||||
"failed": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
{
|
||||
"kind": "candidate",
|
||||
"jsonSha256": "1a7f58af351f003c24491660580c7565fcb6f46203ec641837c06cf39ced9f14",
|
||||
"total": 103,
|
||||
"passed": 103,
|
||||
"failed": 0,
|
||||
"skipped": 0
|
||||
}
|
||||
],
|
||||
"mutations": [
|
||||
{
|
||||
"slug": "transcript-non-tail-reset",
|
||||
"owner": "ui/src/components/task-chat/transcript-adapter.ts",
|
||||
"title": "tags agent messages streamed inside a live run turn as interstitial",
|
||||
"sourceSha": "b1895fa6038b65e4d7fab3773dc1ea83ec1a35892d1b001142b14b275e7b1ae1",
|
||||
"replacements": 1,
|
||||
"mutation": {
|
||||
"before": "if (it.kind === \"message\" && idx !== messageIndex) it.streaming = false;",
|
||||
"after": "if (it.kind === \"message\" && idx !== messageIndex) it.streaming = true;"
|
||||
},
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"caseStatus": "passed",
|
||||
"jsonSha256": "298db52c7b3cd9636c1dfcc50b403e278bdd35a3e8f72156973bb77b9e1c294f",
|
||||
"logSha256": "8ab8ab05ce7559f4de16ffd01ed68c7ce0aa847401f129bcea8bf449cc2ac206"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"caseStatus": "failed",
|
||||
"intendedAssertionFailure": "AssertionError: expected true to be false // Object.is equality",
|
||||
"jsonSha256": "bc2ffc949c5982f6975a48356631cf044f272950a6567815895e6b312a48dca0",
|
||||
"logSha256": "1eff4e160b2a4237619c4849d5c6896fc8d627ce24c72b18393328aff9d22b4f"
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "transcript-message-timestamp",
|
||||
"owner": "ui/src/components/task-chat/transcript-adapter.ts",
|
||||
"title": "tags settled-history messages interstitial too, so live and history agree",
|
||||
"sourceSha": "b1895fa6038b65e4d7fab3773dc1ea83ec1a35892d1b001142b14b275e7b1ae1",
|
||||
"replacements": 1,
|
||||
"mutation": {
|
||||
"before": "atMs: Number.isFinite(atMs) ? atMs : undefined,",
|
||||
"after": "atMs: Number.isFinite(atMs) ? atMs + 1 : undefined,"
|
||||
},
|
||||
"restoredByteForByte": true,
|
||||
"positive": {
|
||||
"exit": 0,
|
||||
"caseStatus": "passed",
|
||||
"jsonSha256": "03eadad261cf00b8294cffe69d300e521c370d5e939c8cfd585c38c55b90ea25",
|
||||
"logSha256": "ff2883bd26a884dacfafb56fa698259aa6023d2526ee3d982ddffc2c6a50d1de"
|
||||
},
|
||||
"negative": {
|
||||
"exit": 1,
|
||||
"caseStatus": "failed",
|
||||
"intendedAssertionFailure": "AssertionError: expected 1785499200001 to be 1785499200000 // Object.is equality",
|
||||
"jsonSha256": "cff42697f265879a73202f701d39fac703788a5bf26ebe236e47e943227a101b",
|
||||
"logSha256": "4736d9727f5398ac9009afd0498ad19529009d7d4eee639743f40b875f9e3103"
|
||||
}
|
||||
}
|
||||
],
|
||||
"allProductionOwnerBytesRestored": true,
|
||||
"productionLinesChanged": 0,
|
||||
"priorUiProofUnchanged": {
|
||||
"commit": "51dc1eb69f5c52d6ef0e29cd2e4061da6c88871f",
|
||||
"files": {
|
||||
"doc/plans/2026-10-12-test-audit-r7-ui.md": "896b9928af85a4c7d588dfca93484980aadb238bd79d8142e671c62f0b191fa8",
|
||||
"doc/plans/2026-10-12-test-audit-r7-ui-controls.json": "0d445f6f066032f2d9cd724525a8d7d2290246cbfeee1f6ab4b44818467af2a7",
|
||||
"doc/plans/2026-10-12-test-audit-r7-ui-appdetail.md": "715f23cd27502c92d0f5d1b83b91bcac03f254c73ab63b44181ae76939805229",
|
||||
"doc/plans/2026-10-12-test-audit-r7-ui-appdetail-controls.json": "7906fde0d62e14a7511b5cf45f864c9386a4c377922333eefc7f7e703c832f6a"
|
||||
}
|
||||
},
|
||||
"discardedAttempt": "Initial candidate clipped the suite-closing statement and failed to parse; regenerated from baseline before accepted full-file run. No result from that attempt counts as proof.",
|
||||
"ciInclusion": "@paperclipai/ui project in general-workspaces-a; complete file remains included; no routing changes",
|
||||
"combinedNetTestLinesRemoved": 386,
|
||||
"combinedRegisteredInvocationsRemoved": 4,
|
||||
"combinedCompleteFileBaselineCases": 333,
|
||||
"combinedCompleteFileCandidateCases": 329,
|
||||
"finalPolishedSourceRun": {
|
||||
"candidateSha256": "f79f72eb7d5f43e26fb0ac9f614887786dabea6f82af12e64446aba5fa54e03c",
|
||||
"jsonSha256": "1cdd87edeed3e2801bcb6aeaab417ae87452bced5daf8f3436ac52bc1ded9aef",
|
||||
"total": 103,
|
||||
"passed": 103,
|
||||
"failed": 0,
|
||||
"skipped": 0
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
# Test audit, Round 7 UI — transcript follow-up
|
||||
|
||||
This follow-up removes **two duplicate registered invocations, two parser calls, and 15 net test lines (14 from the migrations and one blank-line cleanup)** from `ui/src/components/task-chat/transcript-adapter.test.ts`. It adds no helper and changes zero production lines. Combined with the [first UI batch](2026-10-12-test-audit-r7-ui.md) and [AppDetail migration](2026-10-12-test-audit-r7-ui-appdetail.md), the branch removes **386 net test lines and four registered invocations**. Helper cleanup accounts for 320 lines; the three retirement/migration batches account for 65, with one additional blank-line cleanup. No wall-time or CI-speed claim is made.
|
||||
|
||||
The transcript audit base is `51dc1eb69f5c52d6ef0e29cd2e4061da6c88871f`. This file still has its original Round 6 parent bytes at that base. Prior UI tests and reports remain unchanged.
|
||||
|
||||
## Exact migrations
|
||||
|
||||
| Retired registration | Retained keeper | Exact observations carried |
|
||||
|---|---|---|
|
||||
| `marks only the message still open at the tail as streaming` | `tags agent messages streamed inside a live run turn as interstitial` | Original kind-narrowing guard, first message streaming=false, tail message streaming=true. |
|
||||
| `stamps atMs from the first streamed chunk` | `tags settled-history messages interstitial too, so live and history agree` | Original kind-narrowing guard, first timestamp Date.parse(TS), second timestamp Date.parse("2026-07-31T12:00:05.000Z"). |
|
||||
|
||||
Within each pair, the stream array, runId, running state, parser call and message-filter predicate match exactly. The live retired case uses an intermediate items variable; its parser expression and subsequent filter match the keeper's direct chain. Both scopes resolve stream to the same enclosing constant. The settled pair already uses the same direct chain. No hooks, mocks or producer state differ between paired cases. Existing keeper length and interstitial/settled-streaming assertions remain.
|
||||
|
||||
Live running=true and settled running=false remain distinct. **`marks no message streaming when the tail is a tool call` remains byte-identical.** Every other case remains byte-identical, including saved plans, final replies, provider activity, native response-wake authority, thinking state, tool identity, usage, grouping and timeline boundaries.
|
||||
|
||||
TaskChatThread calls the actual transcript parser and settledRunChildren for its run segments. The parser assigns each message timestamp from its first transcript entry and resets non-tail streaming state after the full input. The owner is `ui/src/components/task-chat/transcript-adapter.ts`. The complete suite remains included in `@paperclipai/ui` / `general-workspaces-a`; no CI routing or skip policy changes.
|
||||
|
||||
## Evidence
|
||||
|
||||
| Complete transcript file | Registered cases | Passed | Failed | Skipped |
|
||||
|---|---:|---:|---:|---:|
|
||||
| Baseline | 105 | 105 | 0 | 0 |
|
||||
| Candidate | 103 | 103 | 0 | 0 |
|
||||
|
||||
Run from `ui/`: `pnpm exec vitest run src/components/task-chat/transcript-adapter.test.ts`.
|
||||
|
||||
The audit checks parser inputs and filter ASTs, inserts the original three statements from each retired body, and compares the entire candidate/original program outside those declared migrations. It also reconstructs candidate text from exactly the two removals and two insertions, requiring byte equality. All other source bytes stay unchanged outside the declared blank-line cleanup before the enclosing describe closes. The initial edit clipped the enclosing suite boundary and failed to parse; the temporary codemod was corrected and the candidate regenerated from pinned source before the accepted run. That attempt supplies no passing evidence.
|
||||
|
||||
Both positive keeper controls passed. Both deliberate production regressions failed at the intended migrated assertion:
|
||||
|
||||
| Regression | Intended failure |
|
||||
|---|---|
|
||||
| Leave completed non-tail messages streaming | Live keeper expected false and received true for messages[0].streaming. |
|
||||
| Shift parsed message timestamps by one millisecond | Settled keeper expected 1785499200000 and received 1785499200001 for messages[0].atMs. |
|
||||
|
||||
Neither control failed on setup, timeout or a different assertion. The production owner was restored byte for byte after each mutation and matched pinned Git bytes. Name-filtered controls select one keeper; unselected cases are not full-suite evidence.
|
||||
|
||||
[Transcript controls](2026-10-12-test-audit-r7-ui-transcript-controls.json) retain the exact source hashes, body-audit digest, migration map, complete-file counts, mutation descriptions, intended failures, run/log digests, prior proof hashes and byte-restoration receipts. Temporary raw verifiers/logs are identified by digests but not preserved in full. Across the three separate baseline/candidate packets, all thirteen complete files total 333 baseline cases and 329 candidate cases. After removing one extra blank line, a final complete-file replay passed all 103 cases on the polished source bytes. A delivery-head combined replay remains separate PR evidence.
|
||||
@@ -0,0 +1,74 @@
|
||||
# Test audit, Round 7 UI — preservation report
|
||||
|
||||
This UI batch removes **364 net test lines and one registered invocation** from three files. It changes **zero production lines**. Of the 364 lines, 320 come from helper cleanup and 44 from retiring the duplicate after its fixture/assertion migration. The helper cleanup reduces maintenance code; it makes no wall-time or CI-speed claim. The one retired invocation avoids one duplicate rendered roster scenario.
|
||||
|
||||
The branch starts at pinned parent `e868e6645ce0d598d756d3458f0b3d71afd6db4a`, the head of [Round 6, PR #16047](https://github.com/paperclipai/paperclip/pull/16047). It follows OpenClaw's [test-audit skill](https://github.com/openclaw/openclaw/blob/main/.agents/skills/test-audit/SKILL.md) and [campaign process](https://github.com/openclaw/openclaw/blob/main/.agents/skills/test-audit/CAMPAIGN.md). All ten Round 6 test files were excluded. Prior cleanup remains in the parent history.
|
||||
|
||||
## Scope and cost
|
||||
|
||||
| File | Net test lines removed | Source helper calls expanded | Registered invocations removed |
|
||||
|---|---:|---:|---:|
|
||||
| `ui/src/pages/InviteLanding.test.tsx` | 132 | 18 | 0 |
|
||||
| `ui/src/pages/Agents.test.tsx` | 136 | 16 | 1 |
|
||||
| `ui/src/components/Layout.test.tsx` | 96 | 26 | 0 |
|
||||
| Total | 364 | 60 | 1 |
|
||||
|
||||
Each helper contains one synchronous `root.render` statement. It creates the same complete JSX subtree on each call. The invitation helper also creates a fresh initial-route array. Helpers accept the existing root and query client. They create no root or query client, add no await, and contain no assertion. The roster helper retains QueryClientProvider → ToastProvider → Agents. The distinct table render of production and streamlined AgentList remains inline. Every original outer `act`, flush, timer, input, assertion, cleanup and provider order remains, outside the single declared migration below.
|
||||
|
||||
The audit read the actual invitation, roster and shell owners, their App routes, production-shell/roster counterparts, current tests and source history. It inspected analogous invitation-access, shell-route, company-selection, sidebar, plugin-overlay and roster surfaces. Permission gates, membership/account cache checks, keyboard/hover controls, accessibility, pending state and routing cases retain their own registrations.
|
||||
|
||||
## Exact retirement and keeper
|
||||
|
||||
Retired: Agents `uses the built-in agents route segment as the built-in filter`.
|
||||
|
||||
Keeper: Agents `shows and filters built-in agents when the experimental flag is enabled`.
|
||||
|
||||
Both cases came from commit `8b6a06ee254` and use `/agents/builtin`, the enabled built-in flag, and the same built-in and regular agent/org rows. The keeper now copies the retired case's exact setup, including the populated BuiltInAgentState.agent pointing to the same built-in object as the agent list. It also carries the retired `1 agent` assertion. Its original checks remain: company-scoped built-in API request, Built-in tab text, included built-in name, excluded regular name, absent old badge, and no redirect to the all-agents route.
|
||||
|
||||
The former keeper's null nested agent fixture does not supply a separate ready/list behavior: the actual roster uses entry.agentId and entry.status on that path. The setup modal is not mounted for a ready entry. Copying the retired populated fixture preserves the stronger keeper's observations while retaining every retired observation. Other built-in enable/disable and production-versus-streamlined registrations remain.
|
||||
|
||||
No other case retires. In particular, invitation error presentation remains distinct from its accessibility guard and membership/cache timing cases. Layout route variants retain all original parameter rows and loop iterations. Roster environment-loading, single-environment, disabled-feature and fallback-provider cases remain separate.
|
||||
|
||||
## Complete-file evidence
|
||||
|
||||
| Run | Complete files | Passed cases | Failures | Skips |
|
||||
|---|---:|---:|---:|---:|
|
||||
| Original changed owners | 3 | 71 | 0 | 0 |
|
||||
| Original owner siblings | 8 | 79 | 0 | 0 |
|
||||
| Candidate changed owners | 3 | 70 | 0 | 0 |
|
||||
| Final candidate owners and siblings | 11 | 149 | 0 | 0 |
|
||||
|
||||
The original total is 150, compared with candidate 149. These are actual Vitest registrations, including table rows. The sixty helper counts are source call expansions, not retired executions. Complete-file runs have no name filter. Separate name-filtered mutation controls intentionally select one keeper and do not count their unselected cases as complete-suite proof.
|
||||
|
||||
Commands run from `ui/` use `pnpm exec vitest run` followed by the complete file paths. Changed-owner paths are `src/pages/InviteLanding.test.tsx`, `src/pages/Agents.test.tsx` and `src/components/Layout.test.tsx`. Siblings are SidebarAgents, ActiveAgentsPanel, access/InvitesSection, useCompanyInviteAccess, shell-navigation, company-selection, PluginAppShellOverlays and SidebarShell.
|
||||
|
||||
Dependencies were installed offline with the frozen lockfile in this checkout. Initial dependency-link exploration and two startup-error attempts were discarded; none counts as baseline proof. Accepted runs use this checkout's workspace packages.
|
||||
|
||||
## Expansion and intended regressions
|
||||
|
||||
The verifier expands the actual helper bodies at all sixty call sites, then compares complete original and candidate ASTs. They match outside removal of the named duplicate, its exact setup migration, and insertion of its count assertion into the keeper. Location/comment/raw-format metadata and whitespace-only JSX text are ignored; executable values and statement order are retained. Root/client argument names are checked at each call. Independent review also checks lexical binding, provider nesting and fresh JSX/route values; AST substitution alone does not establish binding correctness.
|
||||
|
||||
All three positive keeper controls passed. All deliberate production regressions failed at the intended retained assertion:
|
||||
|
||||
| Mutation | Intended failing keeper observation |
|
||||
|---|---|
|
||||
| Return all agents from the built-in filter | Migrated `1 agent` count guard. |
|
||||
| Omit actual invite auth aria-invalid state | Email input's fixed `aria-invalid === "true"` guard. |
|
||||
| Bypass the settings sidebar branch | Visible Company settings sidebar guard. |
|
||||
|
||||
These failures are direct assertions, not timeout/setup/worker errors. Each owner was restored byte for byte and checked against the pinned Git source. The final diff has no production changes. Mutation controls use fixed literal expected values from the original tests; helpers supply no oracle.
|
||||
|
||||
## Provenance and limits
|
||||
|
||||
[Controls JSON](2026-10-12-test-audit-r7-ui-controls.json) records exact original/candidate source hashes, all sixty expansion counts, the retirement map, decisions for all 71 original owner registrations, complete-file results, intended failures, raw-run digests, and source-restoration receipts. Raw expansion scripts and logs were temporary audit packets. Digests identify them but do not preserve their full payloads.
|
||||
|
||||
The required token gate and diff whitespace check passed. Workspace typecheck/build, broad default tests and latest-head CI/Greptile status belong in the PR so this preservation report does not confuse focused proof with whole-workspace success. No tests, workflow, dependency, production, retry, timeout or skip policy was weakened to make checks pass.
|
||||
|
||||
## Integration with current master
|
||||
|
||||
During replay after #16047 landed, the retired Priority-filter case had gained
|
||||
three assertions for the agent-created-task checkbox. Those assertions moved
|
||||
to the retained same-input grid/render case, which already enables that filter.
|
||||
The label and initial unchecked state remain covered; no new contract is removed.
|
||||
Fresh PR CI validates the integrated source. Historical controls above remain
|
||||
evidence for their recorded revisions.
|
||||
@@ -0,0 +1,18 @@
|
||||
# Test audit R9: owner-level duplicate consolidation
|
||||
|
||||
Base: `77408fa6c3d7c916d7160760eae2144aaa0f8fe7` (#16072). This batch removes nine registered tests and 79 net test lines. It changes no production code. No CI timing claim was measured.
|
||||
|
||||
| Retired proof | Keeper and preserved contract | Owner mutation caught by keeper |
|
||||
| --- | --- | --- |
|
||||
| CLI ZIP: separate binary blob and invalid UTF-8 fallback cases | Archive round-trip keeps blob bytes and invalid UTF-8 note bytes exact; valid UTF-8 blob input is covered there too. | Bypass blob storage or decode invalid UTF-8 lossily; exact round-trip fails. |
|
||||
| Daytona: first execute creates a session before the second reuses it | Persistent-shell case checks one created session, a `paperclip-` id, and the same session id for both commands. | Break the id prefix or session-store hit; the keeper fails. |
|
||||
| Shared account handle: plain `acct-42` acceptance | Whitespace-rejection case retains the exact accepted input and checks it is not trimmed. | Return null for the accepted identifier; the keeper fails. |
|
||||
| Loopback bind: bare `pnpm dev` rewrite | Loopback-preset case retains the same bare command and checks the rewritten command plus preset behavior. | Stop rewriting the bare command; the keeper fails. |
|
||||
| Native runner: generic remote-runner acceptance | Remote Dot capability case retains generic-remote acceptance alongside the Dot-specific rejection and acceptance controls. | Require Dot capability for generic remote runners; the keeper fails. |
|
||||
| Auth route: null Sentry DSN in an unset configuration | Full persisted-user session response already checks `sentryDsn: null` and `sentryEnvironment: null`. | Return an empty string for the DSN; full response equality fails. |
|
||||
| Discord registration: successful registration before runtime enablement | The 503 refresh case first proves successful registration, capabilities, callback, persisted receipt, token exclusion, and idempotent reconciliation. | Persist the bot token in the receipt; the migrated token-exclusion assertion fails. |
|
||||
| Slack OAuth: organization grant over-grant provenance | The no-scope refresh case first checks the original database grant before refresh, then retains the post-refresh warning. | Omit OAuth provenance when creating the initial organization grant; the pre-refresh database assertion fails. |
|
||||
|
||||
Each mutation was tested against the intended retained assertion. Production owners were restored byte-for-byte after controls. Complete owner candidates passed before restoration. The modified files were then replayed on this exact base in two runs: six owners passed 1,001 tests; after building the local plugin SDK dependency, the two server owners passed 1,691 tests. The final combined total is 2,692 passing tests across all eight changed owners. `git diff --check` passes.
|
||||
|
||||
The reductions consolidate proof at an existing owner and keep the distinct boundary controls. They do not claim a specific CI-time reduction; the focused suites still exercise their retained inputs and assertions.
|
||||
@@ -0,0 +1,57 @@
|
||||
# IssueChatThread test audit: round 18
|
||||
|
||||
Exact parent: #16091, `dc6cfe7512d5dcb25aa9df5b918d46f35cd2eb22`.
|
||||
|
||||
The complete IssueChatThread owner has 89 declarations and 99 registered rows before this change. The candidate has 87 declarations and 97 rows. All rows and parameter tables outside the two retirements remain intact. The paired TaskChatThread owner has 107 declarations and 225 rows. It has no qualifying cut. Native and legacy modes have separate owners and contracts.
|
||||
|
||||
## Retirement map
|
||||
|
||||
| Retired invocation | Retained invocation | Preserved proof and phase |
|
||||
| --- | --- | --- |
|
||||
| omits the bottom spacer when the composer is hidden | drops the count heading and does not use an internal scrollbox | Same fresh root and renderIssueThread(root, { showComposer: false }); migrate the spacer query and null assertion after initial render, before unmount. |
|
||||
| keeps the composer floating with a capped editor height | does not restore the composer viewport for passive live updates by default | Same fresh root and renderIssueThread(root); migrate dock, composer and editor queries and every observation after initial render, before the keeper's liveRuns rerender. |
|
||||
|
||||
The AST comparison permits only these two declaration removals and exact observer moves. Helpers, hooks, provider inputs, fixtures, cleanup, actions, and parameter rows match the parent. The final runtime case names match the baseline minus the two named retirements. The active composer viewport case stays separate because it changes preservation state and snapshot position. No helper was added.
|
||||
|
||||
## Replay
|
||||
|
||||
All full-file runs have zero failed or skipped cases.
|
||||
|
||||
| Phase | Passed cases |
|
||||
| --- | ---: |
|
||||
| Parent baseline | 99 |
|
||||
| Candidate | 97 |
|
||||
| Original test revert | 99 |
|
||||
| Restored candidate after controls | 97 |
|
||||
| Unchanged TaskChatThread sibling | 225 |
|
||||
|
||||
Command: `pnpm exec vitest run ui/src/components/IssueChatThread.test.tsx --reporter=json --outputFile=<phase>.json`. The sibling uses the same command with TaskChatThread.test.tsx.
|
||||
|
||||
## Production controls
|
||||
|
||||
Each control changes the real IssueChatThread.tsx owner. Each selected keeper fails once at the migrated assertion below. Other cases are filtered with Vitest -t; no test-source skip was added.
|
||||
|
||||
| Control | Retained guard | Candidate line |
|
||||
| --- | --- | ---: |
|
||||
| hidden-spacer-leak | `expect(spacer).toBeNull()` | 425 |
|
||||
| missing-dock | `expect(dock).not.toBeNull()` | 3938 |
|
||||
| dock-sticky | `expect(dock?.className).toContain("sticky")` | 3939 |
|
||||
| dock-bottom-offset | `expect(dock?.className).toContain("bottom-(--sz-calc-8)")` | 3940 |
|
||||
| dock-layer | `expect(dock?.className).toContain("z-20")` | 3941 |
|
||||
| missing-composer | `expect(composer).not.toBeNull()` | 3946 |
|
||||
| composer-radius | `expect(composer?.className).toContain("rounded-md")` | 3947 |
|
||||
| composer-padding | `expect(composer?.className).toContain("p-(--sz-15px)")` | 3949 |
|
||||
| editor-height-cap | `expect(editor?.dataset.contentClassName).toContain("max-h-(--sz-28dvh)")` | 3954 |
|
||||
| editor-overflow | `expect(editor?.dataset.contentClassName).toContain("overflow-y-auto")` | 3955 |
|
||||
| editor-min-height | `expect(editor?.dataset.contentClassName).not.toContain("min-h-(--sz-72px)")` | 3956 |
|
||||
| editor-drop-target | `expect(editor?.dataset.fileDropTarget).toBe("parent")` | 3957 |
|
||||
|
||||
The radius positive and negative guards cover the same behavior. The wrong-radius control fails the stronger positive guard; no separate negative-radius mutation is claimed. Production source was restored after every control. SHA256 before and after: `23624e4e25b60c9ce8cc91fa548bfd46e18666723e5aa8d9f882846ded3bdf82`. Candidate test SHA256: `d2361cefd481433b7b5dabd0066b09fa6856f38e3610f910e02e8aab2b3023e3`.
|
||||
|
||||
## Scope and checks
|
||||
|
||||
The test diff adds 29 lines and removes 55 lines: 26 net test lines removed. It removes two registered executions and two fresh initial root/component renders. No measured runtime savings are claimed. Production LOC changes: zero. Keyboard, hash/manual scroll, permissions, retry, persistence, live update, file input, and parameterized cases remain distinct.
|
||||
|
||||
Focused UI typecheck, token gate, and diff check pass. The first UI typecheck could not resolve generated plugin SDK declarations in the fresh checkout. Building the SDK and shared dependency restored the declarations; the rerun passed. Full repository gates are reported in the PR; this focused proof does not claim they passed.
|
||||
|
||||
Local replay JSON, logs, complete declaration/runtime ledgers, exact AST proof and mutation failures are preserved under /private/tmp/issue-chat-*. The concise evidence above is included here so the retirement map and observed controls remain reviewable without local artifacts.
|
||||
@@ -0,0 +1,55 @@
|
||||
# Execution-target sandbox test audit: round 19
|
||||
|
||||
Exact parent: #16092, `8e52b1935d8982fae24158fc94dacf218c023ee5`.
|
||||
|
||||
Read the complete 6,409-line test owner, all helpers, hooks, parameter rows and assertions. The declaration ledger has 129 declarations and 148 registered cases. The candidate has 128 declarations and 147 cases.
|
||||
|
||||
## Retirement map
|
||||
|
||||
Retire `bounds the pre-READY buffer growth-copy work by the bytes received`. Keep `bounds the pre-READY newline-scan work by the bytes received`.
|
||||
|
||||
Move `resetBufferGrowthCopyUnits()` before the keeper's bridge bring-up. Move the exact `readBufferGrowthCopyUnits()` and `copyUnits <= 4 * totalBytes` observation into its try block after the scan bound. Keep both bridge-presence/open-count guards and the exact bridge.stop/api.close finally block.
|
||||
|
||||
Both cases have the same recording API server, buffer cap, 64-byte chunks, chunk count, byte count, runner callback, recorder, provider target, readiness timeout and bridge options. The callback emits the same chunks in the same order. The setup, callback, bridge call and finalizer AST match after normalizing only two namespace labels. Fresh temp prefixes and runIds differ. They select fresh isolated paths and run namespaces; neither case dispatches a request or observes those names. They have the same path shape and valid runId character class. These differences are expressly assessed as isolation, not described as literal byte-equivalent inputs.
|
||||
|
||||
The two reset/read pairs use independent numeric accounting variables. Production never reads the counters to select behavior. Neither reset changes the buffer, gate, callbacks or lifecycle. Both bounds can observe one fresh bridge execution.
|
||||
|
||||
The whole-program AST permits only one declaration removal and the exact reset/read/bound migration. Helpers, hooks, fixtures, parameter rows, all other declarations and the separate many-small-chunk cap case match the parent. The restored runtime case list equals the baseline minus the named retirement.
|
||||
|
||||
## Full owner replay
|
||||
|
||||
All complete-file runs have zero failures and skips.
|
||||
|
||||
| Phase | Passed cases |
|
||||
| --- | ---: |
|
||||
| Exact parent baseline | 148 |
|
||||
| Candidate | 147 |
|
||||
| Original test revert | 148 |
|
||||
| Restored candidate after controls | 147 |
|
||||
|
||||
Command: `pnpm exec vitest run packages/adapter-utils/src/execution-target-sandbox.test.ts --reporter=json --outputFile=<phase>.json`.
|
||||
|
||||
## Actual production-owner controls
|
||||
|
||||
Each control selects the keeper with Vitest `-t`. It fails once at the intended assertion. Other rows are selector-filtered; no source skips are added. Neither control changes the counters or their test-only readers.
|
||||
|
||||
| Control | Actual owner change | Intended failure |
|
||||
| --- | --- | --- |
|
||||
| Newline rescan | Search from offset zero for retained buffers up to 32 KiB, then use the original cursor. This makes actual indexOf work repeat on retained bytes. | Retained scan bound, candidate line 4591: 8,638,528 scan units exceeded 1,065,216. |
|
||||
| Per-fragment growth | In appendReadinessBytes, allocate exactly the needed length for the first 32 KiB, then use the original doubling. This makes actual storage.copy work repeat. | Migrated copy bound, candidate line 4593: 8,863,744 copied bytes exceeded 1,065,216. |
|
||||
|
||||
The bounded controls avoid excessive stress while introducing a real buffer/cursor regression. The owner is restored after each control. SHA256 before and after: `9f61140f7c27698e7837b97dd78f9b3056045a41527da06bb0cee9f11c9f62a6`.
|
||||
|
||||
Candidate test SHA256: `270701dcf459289a6d09ac88c74cf9ccfb41ab8323d75eecbc9ef683072471ee`.
|
||||
|
||||
An initial harness refused the growth declaration because the text occurred in two functions. It applied no growth mutation. The final control binds the exact appendReadinessBytes function. Both final controls caught the intended regressions and restored the owner.
|
||||
|
||||
## Scope and checks
|
||||
|
||||
The test diff adds one line and removes 38 lines: 37 net test lines removed. It removes one registered execution and one real bridge bring-up. No measured time savings are claimed. Production LOC changes: zero.
|
||||
|
||||
Retain all transport, callback, command, host/sandbox path, credential, platform, readiness, timeout, security and lifecycle distinctions. Pre-preface overflow and post-preface overflow remain separate. Safe GET and committed POST remain separate. The independent many-small-chunk buffer-cap case remains intact.
|
||||
|
||||
Focused adapter-utils typecheck and build, token gate, and diff check pass. No repeated broad run was started: the exact parent's full local attempt failed in its server-only phase with unchanged host/server failures before workspace projects ran. Its focused UI proof and all 53 remote checks passed. This candidate does not claim a full local suite pass.
|
||||
|
||||
Full replay JSON/logs, exact declaration/runtime ledger, AST/input proof, mutation failures, original source and restored hash receipts are retained under /private/tmp/execution-target-*. This report includes the retirement map, exact counts and observed controls for review without those local files.
|
||||
@@ -0,0 +1,45 @@
|
||||
# Command-managed-runtime upload duplicate retirement — 2026-10-13
|
||||
|
||||
## Scope and baseline
|
||||
|
||||
- Base: `418eb4623ae767b5c9ce28c1c3e9fcb98f63702e`, the head of [PR #16173](https://github.com/paperclipai/paperclip/pull/16173).
|
||||
- Branch: `codex/test-audit-r19-adapter-utils-upload-case`, stacked on `codex/test-audit-r18-worktree-config`.
|
||||
- Production owner: `createCommandManagedRuntimeClient().writeFile` in `packages/adapter-utils/src/command-managed-runtime.ts`. `prepareCommandManagedRuntime` constructs this client for command-backed adapter staging and fallback sync operations.
|
||||
- Owner file: `packages/adapter-utils/src/command-managed-runtime.test.ts`.
|
||||
- Method: [OpenClaw test-audit](https://github.com/openclaw/openclaw/blob/main/.agents/skills/test-audit/SKILL.md), its audit workflow, owning-boundary guide, and proof policy.
|
||||
- Required repository guidance, contributor rules, roadmap, and PR template were consulted. GitHub searches for the exact case and upload-test consolidation found no duplicate retirement. Related adapter audit: [PR #16115](https://github.com/paperclipai/paperclip/pull/16115).
|
||||
|
||||
## Retirement and retained proof
|
||||
|
||||
Retire only `test_single_stream_writeFile_collapses_roundtrips_under_96MiB`, originally at line 921. It was added in `030dd9d15c` ([PR #10340](https://github.com/paperclipai/paperclip/pull/10340)) as Research A1 proof for the single-stream round-trip reduction. Its two real-shell uploads duplicate the existing transport owner cases.
|
||||
|
||||
Before removal, strengthen the existing single-stream case at line 462 from 3 MiB to 9 MiB. This preserves the retired case's exact size witness. Its payload still contains every byte value, and it still checks exact file bytes, two total shell calls, cleanup, stdin transport, monotonic progress, and final progress. Change the existing base64 guard to allow exactly a 9 MiB source buffer. The guard checks decoded buffer length, not the resulting string length.
|
||||
|
||||
The production threshold is **96 MiB of encoded base64**, not decoded payload bytes. A 9 MiB payload encodes to 12 MiB. Reverting to chunked uploads for this witness fails the surviving exact two-call assertion. Neither the retired case nor this keeper proves the exact 96 MiB boundary or the above-threshold branch.
|
||||
|
||||
Strengthen the existing 12 MiB chunked-progress case from `calls.length > 2` to `3 + Math.ceil(payload.byteLength / (3 * 1024 * 1024))`: seven total shell calls. The three fixed calls initialize the staged file, rename it, and clean it up. The remaining four calls upload decoded 3 MiB chunks. Its binary-byte, bounded-stdin, monotonic-progress, and final-progress assertions stay intact. This is the retired chunk-count formula applied at the surviving larger payload.
|
||||
|
||||
The 10 MiB partial-final-chunk case, omitted-capability case, cleanup-failure case, and all 22 other cases stay byte-for-byte unchanged. The retired cross-case greater-than assertion is implied by the retained exact counts of two and seven.
|
||||
|
||||
## Cost and lines
|
||||
|
||||
- Remove one case: owner file goes from 28 to 27 cases.
|
||||
- Remove the 23-line declaration and its following blank line. Four existing lines change. Git reports 4 added / 28 removed physical test-file lines: net **24 fewer physical lines**.
|
||||
- Production LOC and support LOC change: zero. This receipt is the only additional tracked file.
|
||||
- Retired fixture performed eight real shell invocations: two single-stream and six chunked. Growing the surviving single-stream payload adds no invocations. Net reduction: **eight shell invocations**.
|
||||
- Retired fixture uploaded 18 MiB. Growing the keeper adds 6 MiB. Net reduction: **12 MiB of decoded upload payload** per owner run.
|
||||
- Prior three-file adapter-utils audit baseline: 87/87 passed. The retired case cost 228.125125 ms. Its original 3 MiB keeper cost 51.266500 ms.
|
||||
- Candidate 9 MiB keeper cost 163.982042 ms. Prior owner duration: 1,495.937988 ms; candidate owner duration: 1,979.989990 ms. These are separate host runs, not a controlled performance comparison. They do **not** establish a suite speedup. The deterministic process and byte reductions are the supported savings.
|
||||
|
||||
## Validation
|
||||
|
||||
- `pnpm exec vitest run packages/adapter-utils/src/command-managed-runtime.test.ts --maxWorkers=1 --reporter=json --outputFile=/private/tmp/test-audit-r19-command-managed-runtime-candidate.json`: **27/27 passed**. Recorded command wall time: 7.421 s, including collection and startup.
|
||||
- `pnpm --filter @paperclipai/adapter-utils typecheck`: passed.
|
||||
- `git diff --check`: passed.
|
||||
- Exact diff inspection confirmed the encoded threshold semantics and fixed overhead in the chunk count. A declaration comparison confirmed exactly one removed case, exactly two changed keepers, and all other 25 cases byte-for-byte unchanged.
|
||||
- No production mutation experiments ran. No production code, dependencies, contracts, UI, or CI routing changed.
|
||||
- Repo-wide typecheck, test suite, and build were not run locally for this narrow retirement. This is focused owner proof; broad CI gates and review remain pending before merge.
|
||||
|
||||
## Risk and disposition
|
||||
|
||||
Low risk with directly retained owner proof. The larger single-stream fixture costs more than the original 3 MiB keeper, and timing savings are modest and unproven at suite level. Independent transport, capability-default, partial-chunk, progress, atomic rename, and cleanup contracts remain. Open a stacked PR for review; do not merge.
|
||||
@@ -0,0 +1,21 @@
|
||||
# Agent adapter validation route fixture audit — 2026-10-13
|
||||
|
||||
Status: remove one duplicate positive test. Based on `github/master` `d67e3507b23041212fa26302ce6de078c5ebcc05`. Owner: `server/src/__tests__/agent-adapter-validation-routes.test.ts`. Production code is unchanged.
|
||||
|
||||
## Fixture consolidation and removed declaration
|
||||
|
||||
The dynamic external-adapter positive now sets an unrelated adapter as disabled. This same retained declaration proves the registered `external_test` adapter remains selectable and asserts both HTTP 201 and the returned adapter type. Remove the weaker duplicate positive that separately asserted only HTTP 201. Keep the disabled-selection rejection cases and the case that permits editing an existing disabled adapter.
|
||||
|
||||
The audit also considered deleting the local `requestApp` helper and replacing its 38 uses with direct `request(app)` calls. Do not include that cleanup here: the direct-request version repeatedly approached or exceeded the 15-second first-test timeout locally, while the focused baseline passed. Keep the helper until a broader timing comparison shows no regression.
|
||||
|
||||
The remaining route declarations continue to cover provider-specific model refresh, credentials, rollback, Runner rollout, Dot authorization, provider admission, validation failures, and partial edits. The production entry point remains `routes/agents.ts`; UI configuration and create/hire flows call these routes. CI discovers this filename in the serialized route/authz lane.
|
||||
|
||||
## Local validation and savings
|
||||
|
||||
The historical serialized weight is 24,906 ms and includes isolated process startup, imports, tests, and teardown. It is not a measured runtime reduction. The change removes one test declaration and about 13 test lines, including its separator. It removes no production lines, and no CI time reduction is claimed.
|
||||
|
||||
Focused exact-head validation passed: `pnpm exec vitest run --project @paperclipai/server server/src/__tests__/agent-adapter-validation-routes.test.ts` reported **44/44 passing** in 29.57 seconds with local bind access. `git diff --check` is also required before commit. Relevant adapter registry/environment siblings remain to be validated if later changes touch their behavior.
|
||||
|
||||
## Integration with current master
|
||||
|
||||
The disabled-adapter fixture moves into the existing dynamic-registration keeper. Newer saved-legacy, harness-selection and native-Codex rollout regression cases from master are retained unchanged.
|
||||
@@ -0,0 +1,25 @@
|
||||
# Agent instruction route graph reuse recheck (2026-10-13)
|
||||
|
||||
Owner: `server/src/__tests__/agent-instructions-routes.test.ts`. Rechecked in `/private/tmp/paperclip-test-audit-pr-stack` at `9b4d0cd872ca1fc897f320cb181fc060f0bd5bf1` without changing its branch. The owner blob is identical to both `codex/test-audit-r15-onboarding-duplicates` at `568ba003a5` and the parent of prior candidate `0e5043c65513ac470208152dd90e0e74b6dcd022`: `4f7a65449b3d5ed70539bec18b1865e18c7648b7`.
|
||||
|
||||
The earlier 34-line candidate removes duplicated module setup, not duplicated endpoint executions. Applied its exact owner patch after the parent explicitly authorized this setup reduction. Test source changes by +16/-50 lines, 853 to 819 lines, net -34. Registered and expanded cases remain 24; removed executions and assertions: zero. Production files changed: zero.
|
||||
|
||||
`registerModuleMocks` duplicated the existing hoisted mock registrations. The existing `hoistModuleGraph` helper loads route and middleware exports once; every test still constructs a fresh app/router and HTTP server. `vi.resetAllMocks` clears implementations and once queues as well as call histories; each test's defaults are rearmed, including the secret normalization implementation formerly preserved by `clearAllMocks`. The route's hire lock map is not used by these fixtures because their actor has no run ID. The existing helper inherits the server's 30-second hook timeout, replacing the previous explicit 60-second per-case preload timeout.
|
||||
|
||||
The complete section from the first test declaration through the final lifecycle mock is byte-identical before and after, SHA256 `6b0b031908125729e8a135878a5d5245fa7a4137520df79ddf295c25ffcd2353`. JSON reports contain identical ordered names for all 24 expanded cases. Retained regressions cover external-root and mislabeled-managed-root instance-admin restrictions; generic patch, hire, direct creation and compatibility endpoints; own/peer read authorization; canonical revisions and forged identity/base-revision rejection; binary and empty downloads; candidate resolution scope; history/diff/restore; adapter merge/replacement and skill-selection preservation.
|
||||
|
||||
Full owner command, with authorized local loopback access:
|
||||
|
||||
```sh
|
||||
node node_modules/vitest/vitest.mjs run --project @paperclipai/server server/src/__tests__/agent-instructions-routes.test.ts --reporter=json --outputFile=/private/tmp/agent-instructions-current-ARM.json
|
||||
```
|
||||
|
||||
| Arm | Passed | Report start-to-suite-end duration |
|
||||
| --- | --- | --- |
|
||||
| Baseline | 24/24 | 20.816 s |
|
||||
| Candidate | 24/24 | 7.268 s |
|
||||
| Candidate repeat | 24/24 | 7.445 s |
|
||||
|
||||
These are local observations on a concurrently used host, with one baseline and no reverse-order control. They support stable candidate behavior, not a quantified performance or CI speedup claim. Two sandboxed attempts stalled at HTTP fixtures and were cancelled (exit 130); they are excluded. Existing provider-trace cleanup warnings also appeared in passing baseline and candidate runs.
|
||||
|
||||
Exact PR-branch rerun also passed 24/24 in 8.06 seconds with `node_modules/.bin/vitest run --project @paperclipai/server server/src/__tests__/agent-instructions-routes.test.ts --silent=true`. `git diff --check` passed. Reports: `/private/tmp/agent-instructions-current-baseline.json`, `/private/tmp/agent-instructions-current-candidate.json`, and `/private/tmp/agent-instructions-current-candidate-repeat.json`. No staging, commit, push, branch switch, or edits to other owners were performed. Repo-wide checks were not run for this narrow test-only worker handoff.
|
||||
@@ -0,0 +1,18 @@
|
||||
# Agent skills route duplicate canonicalization audit — 2026-10-13
|
||||
|
||||
Status: duplicate-proof deletion, based on `github/master` `d67e3507b23041212fa26302ce6de078c5ebcc05`. Owner: `server/src/__tests__/agent-skills-routes.test.ts`. Production code and unrelated declarations are unchanged.
|
||||
|
||||
## Removed declarations and retained keepers
|
||||
|
||||
Remove two successful canonicalization replays:
|
||||
|
||||
- The sync case that sends the `paperclip` alias with `mode: replace` and checks the canonical persisted singleton is covered by the retained complete-replacement case. That keeper starts with an existing assignment, performs the same request and checks the same canonical result. It additionally proves replacement removes the prior assignment.
|
||||
- The hire case that checks canonical desired skills in the approval payload and requested configuration snapshot is covered by the retained detailed hire case. That keeper checks both canonical fields and also preserves agent creation, icon, actor attribution, and source-issue linkage.
|
||||
|
||||
All other declarations remain. The broader suite retains adapter-specific configuration, secret handling, merge/remove/replace semantics, beta gates, built-in role defaults, onboarding trust, approval policy, actor attribution, and rejection boundaries. Production routes, services, and their seams are unchanged. Caller review covered Agent Skills and Company Skills UI, New Agent/onboarding hire flows, and CLI `skills agent sync`.
|
||||
|
||||
## Local validation and savings
|
||||
|
||||
The historical serialized route/authz weight is 24,106 ms and includes suite startup, imports, database setup, and shutdown. It is not a measurement of removable runtime. The edit removes two test declarations and about 48 test lines, including separators. It removes two HTTP requests and their repeated module-reset/import setup. No production lines are removed, and no CI time reduction is claimed.
|
||||
|
||||
The focused exact-head owner suite passed **58/58** in 38.38 seconds. No baseline or mutation run is claimed. A faulty canonicalizer or approval serializer should fail the retained replacement and detailed-hire keepers. The existing skills-service and authorization-service owner suites continue to cover storage and the direct permission decision.
|
||||
@@ -0,0 +1,70 @@
|
||||
# CLI portability codec test audit
|
||||
|
||||
Date: 2026-10-13. Proof base: `06c1b2035df44fa03c065ddd69e8bf8df8513b86` (the preceding audit stack). This candidate changes tests only.
|
||||
|
||||
## Decision and preserved contracts
|
||||
|
||||
Retire `cli/src/__tests__/zip-codec.test.ts` after moving its unique observations into `packages/shared/src/portability-zip.test.ts`:
|
||||
|
||||
| Retired declaration | Shared keeper |
|
||||
| --- | --- |
|
||||
| `matches blobs/ entries at the archive root and under a package root` | Same named classifier keeper, now also rejects `blobs/nested/file`. |
|
||||
| `decodes valid UTF-8 entries to text` | `decodes valid UTF-8 entries to text and falls back to base64 for invalid bytes`, with identical Unicode text/path/result. |
|
||||
| `round-trips blob and invalid UTF-8 entries byte-exactly` | Existing STORE/DEFLATE archive keeper, now using the retired valid-UTF8 blob bytes `[0x68, 0x69]` and adding `notes/raw` with `[0x68, 0x69, 0xff, 0xfe, 0xc0]`. |
|
||||
|
||||
The valid-UTF8 blob is necessary: arbitrary invalid binary bytes can still become base64 through the decoder fallback if opaque-blob classification breaks. The keeper now demands base64 `aGk=` for the ASCII blob, and `aGn//sA=` for invalid non-blob UTF8. Existing STORE, genuine DEFLATE, shared-root, direct UTF8, truncation, descriptor, central-directory, duplicate-path and decompression-limit assertions remain.
|
||||
|
||||
The CLI module is a production re-export of the shared codec. Real consumers remain in `resolveInlineSourceFromPath`, `resolveChunkedImportZip`, folder conversion/filtering (`cli/src/commands/client/company.ts`), and server uploaded-archive parsing (`server/src/routes/companies.ts`). No production exports or code are deleted. CLI file/transport/filtering tests remain in `company-import-zip.test.ts` and `company-import-transfer.test.ts`.
|
||||
|
||||
History: #10507 (`916c13501f`) introduced CLI codec tests. #10531 (`5ec7ce76e5`) moved the codec into shared, retained CLI re-exports, and introduced the primary shared-owner tests. This candidate removes the replay left behind by that ownership move.
|
||||
|
||||
## Reproducible verification
|
||||
|
||||
From a dependency-ready checkout at the proof base, the complete baseline/revert owner command is:
|
||||
|
||||
```sh
|
||||
node node_modules/vitest/vitest.mjs run --no-file-parallelism --maxWorkers=1 \
|
||||
packages/shared/src/portability-zip.test.ts \
|
||||
cli/src/__tests__/zip-codec.test.ts
|
||||
```
|
||||
|
||||
For the candidate/restored owner, omit the deleted CLI file. Run transport proof separately:
|
||||
|
||||
```sh
|
||||
node node_modules/vitest/vitest.mjs run --no-file-parallelism --maxWorkers=1 \
|
||||
cli/src/__tests__/company-import-zip.test.ts \
|
||||
cli/src/__tests__/company-import-transfer.test.ts
|
||||
```
|
||||
|
||||
| Phase | Complete owner | Separate transport |
|
||||
| --- | --- | --- |
|
||||
| Untouched baseline | 18/18 | 18/18 |
|
||||
| Candidate | 15/15 | 18/18 |
|
||||
| Full test-file revert | 18/18 | Not repeated |
|
||||
| Restored candidate | 15/15 | Not repeated |
|
||||
| After production restoration | 15/15 | 18/18 |
|
||||
| After verbose mutation receipts | 15/15 | Not repeated |
|
||||
|
||||
All complete-file positive runs have zero failed, skipped/pending and todo tests. `git diff --check` passes. No tests were disabled or weakened because of failures.
|
||||
|
||||
## Actual production falsification
|
||||
|
||||
Each mutation changes only `packages/shared/src/portability-zip.ts`, is run separately, and is restored byte-for-byte before the next mutation. Focused negative runs select one keeper and therefore skip 14 unrelated cases; each selected case fails at the intended assertion.
|
||||
|
||||
1. Broaden the classifier regex from `/(^|\/)blobs\/[^/]+$/` to `/(^|\/)blobs\/.+$/`. Run shared owner with `-t 'matches blobs/'`. The migrated `blobs/nested/file` assertion fails: expected false, received true.
|
||||
2. Replace `if (isBlobStorePath(pathValue)) {` with `if (false) {` in the conversion function. Run shared owner with `-t 'round-trips STORE'`. The migrated archive assertion fails because `blobs/4f2d1c9a` becomes plain `"hi"` instead of `{ encoding: "base64", data: "aGk=", contentType: "application/octet-stream" }`.
|
||||
3. Replace archive entry conversion `body: bytesToPortableFileEntry(archivePath, entryBytes),` with `body: isBlobStorePath(archivePath) ? bytesToPortableFileEntry(archivePath, entryBytes) : textDecoder.decode(entryBytes),`. Run shared owner with `-t 'round-trips STORE'`. The migrated `notes/raw` assertion fails because lossy text replaces the expected base64 bytes. This preserves the blob branch so the failure specifically witnesses the non-blob invalid-UTF8 archive contract.
|
||||
|
||||
Production SHA256 before and after all mutations: `b5860afd9ab301fb9cd44f3b3799c28d6fe6297fc891ebbe330b4b62bc53bd4e`.
|
||||
Original shared test SHA256: `7d48436c195120e9717d9ee1b99f10c808c976088b6c2306cbfad3990053893a`.
|
||||
Candidate shared test SHA256: `1664aca9760a18f33ce2657a4ac878a6015c8a6a43b4290dd88cd2b78663b6db`.
|
||||
Deleted CLI test SHA256: `e3634f25fa66544937cf12d30432ff8d109fbfbd578b5a6548df5aef1625f8ef`.
|
||||
Candidate patch SHA256: `172b2e5fa01f369cb07edf19a133680c82bb239cdbd44ccb878bf1ef0ea98071`.
|
||||
|
||||
## Cost and limits
|
||||
|
||||
Diff: 9 added and 52 removed test lines, **43 net test lines removed**. Three registrations and one CLI Vitest file are retired; the shared owner stays at 15 cases. Production reduction is zero.
|
||||
|
||||
`scripts/run-vitest-stable.mjs` routes CLI to `general-workspaces-a` and shared to `general-workspaces-b`; `.github/workflows/pr-trusted.yml` executes those groups. This removes duplicate CLI collection/import/case work. No wall-time or CI percentage savings are claimed.
|
||||
|
||||
This is focused local evidence, not a repo-wide PR-ready result. Repo-wide typecheck, full suite, build, CI and reviewer checks were not run by this proof agent and must be attributed separately by the delivery supervisor. No commit or PR was created by this agent.
|
||||
@@ -0,0 +1,221 @@
|
||||
# Proven Codex staging permission-test consolidation
|
||||
|
||||
Historical proof base: #16106 exact head 397459400c6e7b18b462dcac3d8886b390ca8e8c. Original test and production source match exact-head blobs before controls. Isolated snapshot only; serial runs; no shared checkout edits, commits, pushes or PRs.
|
||||
|
||||
Historical result: PROVEN. Owner packages/adapters/codex-local/src/server/codex-home.test.ts shrinks 1,412 -> 1,371 lines (41 net removed); registered cases 53 -> 50; three fixture allocations/stageCodexHomeForSync calls and their teardown sequences retired. No subprocess delta or CI-time improvement claimed.
|
||||
|
||||
Keeper `stageCodexHomeForSync stages exactly the allowlist, derefs auth.json to bytes, and excludes decoys` gains direct actual 0700 staged-root and 0600 checks for auth.json, config.toml, config.json and instructions.md. Retire the standalone auth mode, every-file mode and directory-mode cases. Same buildFakeHome input bytes/action apply; original runId values differ only in temporary-directory prefix. Keeper retains its run-1 prefix, real allowlist/content/symlink/decoy receipts and cleanup. Dedicated secret-bearing managed-MCP config.toml permission case remains independent.
|
||||
|
||||
| Complete-owner phase | Cases | Pass | Fail | Exit |
|
||||
|---|---:|---:|---:|---:|
|
||||
| baseline | 53 | 53 | 0 | 0 |
|
||||
| candidate | 50 | 50 | 0 | 0 |
|
||||
| file-mode-0644-original | 53 | 50 | 3 | 1 |
|
||||
| file-mode-0644-keeper | 50 | 48 | 2 | 1 |
|
||||
| directory-mode-0755-original | 53 | 52 | 1 | 1 |
|
||||
| directory-mode-0755-keeper | 50 | 49 | 1 | 1 |
|
||||
| restored-candidate | 50 | 50 | 0 | 0 |
|
||||
| integrated-stack | 50 | 50 | 0 | 0 |
|
||||
|
||||
Every accepted run has zero pending/todo/skipped cases. Both real regressions produce direct intended filesystem-mode assertion failures, not setup, timeouts or worker failures.
|
||||
|
||||
## Actual production mutations
|
||||
|
||||
- File chmod: in stageCodexHomeEntry's real write path replace explicit fs.chmod(target, 0o600) with 0o644. Actual staged files become group/other readable (420 actual vs 384 expected). Original full owner fails three cases: auth.json mode, managed-MCP config.toml mode, every-file mode. Candidate fails keeper's actual auth.json stat plus the retained managed-MCP case. The duplicate security assertions now live on real staged bytes in keeper.
|
||||
- Directory chmod: add fs.chmod(stagedHome, 0o755) immediately after mkdtemp and before allowlist copying. Actual staged-root mode becomes 493 vs expected 448. Original dedicated 0700 case and keeper's actual root-stat guard both fail. File bytes/permissions and fixture contents remain otherwise unchanged.
|
||||
|
||||
Regressions run one at a time, with full original/candidate owners under identical mutated production bytes. Test/production restores occur in finally and are byte/hash-verified after every pair. Final restored candidate passes 50/50. Source then restores to exact #16106 test and production originals. Fake fixture credentials only; no real Codex home/credentials are accessed, and no production files outside the isolated snapshot are changed.
|
||||
|
||||
## Dependencies and isolation
|
||||
|
||||
The global pnpm installer differed from the repository's pinned pnpm@9.15.4, stalled before installing the graph, and was explicitly stopped/reaped (exit 143). No tests ran under that installer. Historical setup linked immutable third-party packages from a pnpm store. That private dependency receipt is not bundled. The reproduction below uses a fresh install from the pinned lockfile. Workspace shared and adapter-utils links resolve only to source inside the exact-head isolated snapshot; no application/workspace source is borrowed from the shared checkout. Use existing Codex package Vitest config and full explicit owner path; no mocked resolver/helper or custom alias replaces production code. All controls use the same graph.
|
||||
|
||||
## Exact hashes and integrated stack
|
||||
|
||||
- Original test SHA256: 8f7a0497cb4d8a0f8de3d341585e74c8c17203ab93fe69d0d78fc59410beb220
|
||||
- Proven candidate test SHA256: 8615ceaed7c04647bbc2c674448a012d15a6f597eb36c9b2bfbf854baf947cac
|
||||
- Original/restored production SHA256: fd08bc782af5bdc4631d43cc41f156d97daad629d04fa8654d177f549f8b1b9e
|
||||
|
||||
The proven shard, provisioning and Codex test patches all pass git apply --check and apply together without conflict to exact #16106 snapshot. Integrated Codex candidate retains its executed SHA and passes 50/50 with all three patches present. The historical integrated receipt recorded shard test hash `58ecff8ddceecb8e0c44240fa3dbf7ae6a9756dbac35b5ad52a14e655cfc8327`, provisioning test hash `ffacee5de45871dfe9bb2613aa05ffadb452e4c1f7188b8f0519d36d70d935b2`, the Codex candidate hash above, exit 0, 50/50 passing, zero pending/todo and report digest `822a0d3dbf84d01cb6fb62081a7028d77345c4d1526558c920700672fb313dd3`. Afterwards all three tests restore to exact #16106 original bytes. This proves the combined patches apply and Codex owner passes; it does not claim other owners were rerun in the combined state.
|
||||
|
||||
## Inspectable reproduction
|
||||
|
||||
The results above are historical, recorded on 2026-10-13. This documentation repair
|
||||
checks the Git source and mutation hashes; it does not claim fresh test results.
|
||||
Historical raw reports remain local and are not bundled. The relevant failure
|
||||
excerpts and exact executed production edits are included here; no private proof
|
||||
file is needed to reconstruct the checks.
|
||||
|
||||
Run the block from a repository checkout with the public `base` and `head` Git
|
||||
revisions below. Fetch those public PR/revisions first if they are absent.
|
||||
Python 3.12+, Git and Node are required. The UI and Codex recipes also require
|
||||
pnpm 9.15.4 and network access to install dependencies.
|
||||
|
||||
The script uses an isolated snapshot and obtains the candidate test directly
|
||||
from its Git revision. It runs the full baseline and candidate owners, applies
|
||||
each mutation independently, checks the intended failing case, restores exact
|
||||
source bytes in `finally`, and reruns the full candidate. Counts are
|
||||
`[total, passed, failed, skipped-or-filtered]`. Original-owner mutation counts
|
||||
above are historical; this recipe repeats candidate sensitivity checks.
|
||||
Prefix the command with `AUDIT_RECONSTRUCT_ONLY=1` to verify source and mutation
|
||||
hashes without extracting a snapshot, installing dependencies or running tests.
|
||||
|
||||
```sh
|
||||
python3 - <<'PY'
|
||||
import hashlib, io, json, os, re, subprocess, tarfile, tempfile
|
||||
from pathlib import Path
|
||||
|
||||
spec = {'base': '397459400c6e7b18b462dcac3d8886b390ca8e8c',
|
||||
'head': '449f503f75463956aa0c16cf18623c6217b1f01f',
|
||||
'owner': 'packages/adapters/codex-local/src/server/codex-home.test.ts',
|
||||
'kind': 'codex',
|
||||
'hashes': {'packages/adapters/codex-local/src/server/codex-home.test.ts': '8f7a0497cb4d8a0f8de3d341585e74c8c17203ab93fe69d0d78fc59410beb220',
|
||||
'packages/adapters/codex-local/src/server/codex-home.ts': 'fd08bc782af5bdc4631d43cc41f156d97daad629d04fa8654d177f549f8b1b9e'},
|
||||
'candidate_hash': '8615ceaed7c04647bbc2c674448a012d15a6f597eb36c9b2bfbf854baf947cac',
|
||||
'baseline': [53, 53, 0, 0],
|
||||
'candidate': [50, 50, 0, 0],
|
||||
'mutations': [{'name': 'directory-mode-0755',
|
||||
'path': 'packages/adapters/codex-local/src/server/codex-home.ts',
|
||||
'changes': [[' try {\n for (const entry of CODEX_SYNC_ALLOWLIST) {',
|
||||
' await fs.chmod(stagedHome, 0o755);\n'
|
||||
' try {\n'
|
||||
' for (const entry of CODEX_SYNC_ALLOWLIST) {']],
|
||||
'hash': '1b7d02534f024e2f9c4fd6a3bda4604cd3609163e14e3de7dc504847cc1adf5e',
|
||||
'counts': [50, 49, 1, 0],
|
||||
'guard': 'stageCodexHomeForSync stages exactly the allowlist, derefs auth.json to '
|
||||
'bytes, and excludes decoys',
|
||||
'message': 'expected 493 to be 448'},
|
||||
{'name': 'file-mode-0644',
|
||||
'path': 'packages/adapters/codex-local/src/server/codex-home.ts',
|
||||
'changes': [[' await fs.chmod(target, 0o600);\n',
|
||||
' await fs.chmod(target, 0o644);\n']],
|
||||
'hash': '151071d796a14e1bd53a8227d1679f9c30ac73459206fe77481723d151f5118e',
|
||||
'counts': [50, 48, 2, 0],
|
||||
'guard': 'stageCodexHomeForSync stages exactly the allowlist, derefs auth.json to '
|
||||
'bytes, and excludes decoys',
|
||||
'message': 'expected 420 to be 384'}]}
|
||||
|
||||
def digest(data):
|
||||
return hashlib.sha256(data).hexdigest()
|
||||
|
||||
def blob(rev, path):
|
||||
return subprocess.check_output(["git", "show", rev + ":" + path])
|
||||
|
||||
owner = spec["owner"]
|
||||
original = {p: blob(spec["base"], p) for p in spec["hashes"]}
|
||||
candidate = blob(spec["head"], owner)
|
||||
assert all(digest(b) == spec["hashes"][p] for p, b in original.items())
|
||||
assert digest(candidate) == spec["candidate_hash"]
|
||||
mutants = []
|
||||
for m in spec["mutations"]:
|
||||
text = original[m["path"]].decode()
|
||||
for before, after in m["changes"]:
|
||||
assert text.count(before) == 1, (m["name"], "ambiguous mutation")
|
||||
text = text.replace(before, after)
|
||||
data = text.encode()
|
||||
assert digest(data) == m["hash"], m["name"]
|
||||
mutants.append((m, data))
|
||||
if os.environ.get("AUDIT_RECONSTRUCT_ONLY") == "1":
|
||||
print("Original, candidate and all mutation hashes match historical proof.")
|
||||
raise SystemExit(0)
|
||||
|
||||
archive = subprocess.check_output(["git", "archive", spec["base"]])
|
||||
with tempfile.TemporaryDirectory(prefix="paperclip-audit-") as directory:
|
||||
root = Path(directory)
|
||||
with tarfile.open(fileobj=io.BytesIO(archive)) as tar:
|
||||
tar.extractall(root, filter="data")
|
||||
if spec["kind"] != "tap":
|
||||
assert subprocess.check_output(["pnpm", "--version"], cwd=root, text=True).strip() == "9.15.4"
|
||||
subprocess.run(["pnpm", "install", "--frozen-lockfile"],
|
||||
cwd=root, check=True)
|
||||
|
||||
def run(label, expected, mutation=None):
|
||||
report = root / "audit-report.json"
|
||||
if report.exists():
|
||||
report.unlink()
|
||||
if spec["kind"] == "tap":
|
||||
command = ["node", "--test", "--test-reporter=tap", owner]
|
||||
elif spec["kind"] == "ui":
|
||||
command = ["pnpm", "--filter", "@paperclipai/ui",
|
||||
"exec", "vitest", "run", "src/pages/CompanyExport.test.tsx",
|
||||
"--maxWorkers=1", "--reporter=default", "--reporter=json",
|
||||
"--outputFile.json=" + str(report)]
|
||||
else:
|
||||
command = ["node", "node_modules/vitest/vitest.mjs", "run", "--config",
|
||||
"packages/adapters/codex-local/vitest.config.ts", owner,
|
||||
"--reporter=json", "--outputFile=" + str(report)]
|
||||
if mutation and mutation.get("selector"):
|
||||
command += ["-t", mutation["selector"]]
|
||||
result = subprocess.run(command, cwd=root, capture_output=True, text=True,
|
||||
timeout=180)
|
||||
output = result.stdout + result.stderr
|
||||
print(label, "exit", result.returncode, output)
|
||||
if spec["kind"] == "tap":
|
||||
counts = {k: int(v) for k, v in re.findall(
|
||||
r"^# (tests|pass|fail|skipped) (\d+)$", output, re.M)}
|
||||
actual = [counts[k] for k in ["tests", "pass", "fail", "skipped"]]
|
||||
if mutation:
|
||||
failures = re.findall(
|
||||
r"^not ok \d+ - (.*?)\n(.*?)(?=^(?:ok|not ok) \d+ - |^1\.\.|\Z)",
|
||||
output, re.M | re.S)
|
||||
assert any(name == mutation["guard"] and mutation["message"] in body
|
||||
and "ERR_ASSERTION" in body for name, body in failures), label
|
||||
else:
|
||||
data = json.loads(report.read_text())
|
||||
actual = [data[k] for k in ["numTotalTests", "numPassedTests",
|
||||
"numFailedTests", "numPendingTests"]]
|
||||
if mutation:
|
||||
hits = [a for suite in data["testResults"] for a in suite["assertionResults"]
|
||||
if a["status"] == "failed" and mutation["guard"] in a["fullName"]]
|
||||
assert any(mutation["message"] in msg for a in hits
|
||||
for msg in a["failureMessages"]), label
|
||||
if mutation.get("line"):
|
||||
assert any(f'CompanyExport.test.tsx:{mutation["line"]}:' in msg
|
||||
for a in hits for msg in a["failureMessages"]), label
|
||||
assert actual == expected, (label, actual, expected)
|
||||
assert result.returncode == (1 if mutation else 0), label
|
||||
|
||||
try:
|
||||
run("baseline", spec["baseline"])
|
||||
(root / owner).write_bytes(candidate)
|
||||
run("candidate", spec["candidate"])
|
||||
for m, data in mutants:
|
||||
try:
|
||||
(root / owner).write_bytes(candidate)
|
||||
(root / m["path"]).write_bytes(data)
|
||||
run(m["name"] + "-keeper", m["counts"], m)
|
||||
finally:
|
||||
for path, data in original.items():
|
||||
(root / path).write_bytes(data)
|
||||
assert all((root / p).read_bytes() == b for p, b in original.items())
|
||||
(root / owner).write_bytes(candidate)
|
||||
run("restored-candidate", spec["candidate"])
|
||||
finally:
|
||||
for path, data in original.items():
|
||||
(root / path).write_bytes(data)
|
||||
assert all((root / p).read_bytes() == b for p, b in original.items())
|
||||
PY
|
||||
```
|
||||
|
||||
Recorded intended failure excerpts (fixture path prefixes omitted):
|
||||
|
||||
```text
|
||||
directory-mode-0755-original
|
||||
stageCodexHomeForSync creates the staged dir with mode 0700
|
||||
AssertionError: expected 493 to be 448 // Object.is equality
|
||||
directory-mode-0755-keeper
|
||||
stageCodexHomeForSync stages exactly the allowlist, derefs auth.json to bytes, and excludes decoys
|
||||
AssertionError: expected 493 to be 448 // Object.is equality
|
||||
file-mode-0644-original
|
||||
stageCodexHomeForSync writes the staged auth.json with mode 0600
|
||||
AssertionError: expected 420 to be 384 // Object.is equality
|
||||
stageCodexHomeForSync writes the staged config.toml (managed MCP bearer header) with mode 0600
|
||||
AssertionError: expected 420 to be 384 // Object.is equality
|
||||
stageCodexHomeForSync writes every staged regular file with mode 0600
|
||||
AssertionError: auth.json should be staged 0600: expected 420 to be 384 // Object.is equality
|
||||
file-mode-0644-keeper
|
||||
stageCodexHomeForSync stages exactly the allowlist, derefs auth.json to bytes, and excludes decoys
|
||||
AssertionError: auth.json should be staged 0600: expected 420 to be 384 // Object.is equality
|
||||
stageCodexHomeForSync writes the staged config.toml (managed MCP bearer header) with mode 0600
|
||||
AssertionError: expected 420 to be 384 // Object.is equality
|
||||
```
|
||||
@@ -0,0 +1,123 @@
|
||||
# Codex crash reconciliation test audit
|
||||
|
||||
Base: `c1ae082a7a49c239a22e5149e223a41325b0ba2d` (CLI ZIP content uploaded as PR #16118).
|
||||
|
||||
Remove only `requires reconciliation for a classified Codex harness crash`,
|
||||
`server/src/__tests__/heartbeat-retry-scheduling.test.ts:2034–2059`.
|
||||
Saving: **26 test lines and one registered execution**. No runtime reduction is
|
||||
claimed. Keeper: `requires reconciliation for an error-code-only Codex harness
|
||||
crash`, originally lines 2061–2086 (candidate 2035–2060).
|
||||
|
||||
## Static preservation evidence
|
||||
|
||||
The full fixture helper at lines 186–253 writes the classification only into
|
||||
`heartbeatRuns.resultJson.errorFamily`. Both cases then update that run with
|
||||
`resultJson: null` before `heartbeat.scheduleBoundedRetry`. Both persist the same
|
||||
Codex adapter, active agent, failed status, harness-crash error code, zero retry
|
||||
attempts, context shape and company defaults. They call with the same random
|
||||
callback and identical relative `now`/created/updated/finished timestamps. The
|
||||
remaining absolute 12:00 versus 13:00 difference enters no clock comparison with
|
||||
another fixture; no retry deadline, active holder or evidence receipt is seeded.
|
||||
|
||||
Both have one identical literal disposition/code assertion:
|
||||
`{ outcome: "not_scheduled", errorCode: "legacy_execution_requires_reconciliation" }`.
|
||||
No unique assertion needs transfer. The retained error-code-only keeper correctly
|
||||
names the effective input. The classified title no longer reflects classification
|
||||
coverage after its result JSON is erased.
|
||||
|
||||
Production: the exported heartbeat facade delegates `scheduleBoundedRetry` to
|
||||
`server/src/services/heartbeat/retries.ts:1835–1850`, which loads the persisted
|
||||
run with full result JSON and enters `scheduleBoundedRetryForRun`. The real
|
||||
reconciliation guard is at line 501. Its classifier in
|
||||
`server/src/services/legacy-execution-recovery.ts:20–64` requires reconciliation
|
||||
for failed legacy runs without safe bootstrap evidence. Its decision does not
|
||||
consult error family. The subsequent scheduler would create an actual queued
|
||||
wake and scheduled-retry row if that guard were bypassed. It does not launch the
|
||||
provider during this call.
|
||||
|
||||
Non-test callers include run completion (`heartbeat/run-completion.ts:859,
|
||||
1412`), recovery (`heartbeat/recovery.ts:405`), scheduling
|
||||
(`heartbeat/scheduling.ts:668`) and the heartbeat facade. The existing general
|
||||
server CI lane owns this test file; the recorded duration inventory lists it.
|
||||
No new export, injection seam, workflow, production, telemetry or timeout change
|
||||
is needed.
|
||||
|
||||
History: commit `665408c6d01` (PR #10210) added two genuinely different retry
|
||||
classification cases on 2026-07-24. Commit `35fdc0c66b8` (PR #13075) on 2026-09-09
|
||||
renamed both to reconciliation cases, reset both result JSON values and replaced
|
||||
both original assertions with the same reconciliation expectation. That change
|
||||
collapsed their original classification distinction.
|
||||
|
||||
Excluded files from #16114/#16115/#16116/#16075 and the completed UUID-assignee
|
||||
candidate are untouched. Recent audit receipts contain no prior retirement of
|
||||
this pair. All test bytes outside the one removed body stay identical.
|
||||
|
||||
## Complete proof on the exact child base
|
||||
|
||||
| Complete owner/sibling phase | Passed | Failed | Skipped |
|
||||
|---|---:|---:|---:|
|
||||
| Baseline | 66 | 0 | 0 |
|
||||
| Candidate | 65 | 0 | 0 |
|
||||
| Full revert | 66 | 0 | 0 |
|
||||
| Restored candidate | 65 | 0 | 0 |
|
||||
| Final production restore | 65 | 0 | 0 |
|
||||
|
||||
The integration owner has 52 cases before and 51 after. The unchanged extracted
|
||||
retry sibling has 14 cases. All phases run serially in this isolated worktree on
|
||||
exact parent `c1ae082a7a49c239a22e5149e223a41325b0ba2d`. No test execution overlaps
|
||||
the ZIP proof; a process scan confirmed its test processes had exited first.
|
||||
|
||||
```sh
|
||||
node node_modules/vitest/vitest.mjs run --project @paperclipai/server server/src/__tests__/heartbeat-retry-scheduling.test.ts server/src/services/heartbeat/retries.test.ts --exclude '**/dist/**' --pool=forks --maxWorkers=1
|
||||
```
|
||||
|
||||
The unmutated selected keeper passes 1/1. The actual mutation replaces the one
|
||||
`if (await legacyExecutionNeedsReconciliationWithEvidence(db, run))` guard at
|
||||
`server/src/services/heartbeat/retries.ts:501` with
|
||||
`if (false && await legacyExecutionNeedsReconciliationWithEvidence(db, run))`.
|
||||
The same keeper then fails at its exact disposition/code matcher on candidate
|
||||
`heartbeat-retry-scheduling.test.ts:2057:23`. The real scheduler returns an actual
|
||||
scheduled successor instead of the required reconciliation result. That run
|
||||
exits 1 with exactly one selected failure; the other 50 cases are filtered out
|
||||
and are not claimed as complete coverage. The production file is restored
|
||||
byte-for-byte before the final complete 65/65 run.
|
||||
|
||||
Selected command: the integration file only with
|
||||
`-t 'requires reconciliation for an error-code-only Codex harness crash'`.
|
||||
The harness adds default and JSON reporters and a separate output file per phase.
|
||||
Whole-file byte-slice equality proves every test byte outside the single removed
|
||||
body is unchanged. No assertion transfers or production edits are committed.
|
||||
|
||||
## Setup recovery and practical limits
|
||||
|
||||
The first child baseline was rejected: 11 non-database cases passed and 55
|
||||
cases skipped because Postgres could not create its 56-byte SysV tracking
|
||||
segment. An isolated initdb diagnostic confirmed shared-memory-ID exhaustion;
|
||||
`kern.sysv.shmmni` was 32 and all 32 IDs were occupied. This was not a test failure
|
||||
or disk-space failure.
|
||||
|
||||
The authorized guarded recovery removed 18 stale segments. For each segment an
|
||||
immediate `ipcs` read confirmed NATTCH=0 and a process scan confirmed both creator
|
||||
and last-user PIDs absent. All 14 attached segments were preserved. No live
|
||||
Postgres process was stopped, and no kernel limits were changed. Before/after
|
||||
state and per-ID checks are saved in the proof packet's `ipc-cleanup.json`.
|
||||
The exact baseline retry succeeded, followed by all accepted controls above.
|
||||
The rejected setup run is preserved in `rejected-baseline-shm/`.
|
||||
|
||||
This worktree uses its own frozen offline dependencies, native Postgres package
|
||||
symlink hydration, and shared/SDK build prerequisites. The successful source
|
||||
removal is 26 lines and one execution; no CI wall-time improvement is claimed.
|
||||
`git diff --check` passes. Broad typecheck/build and unrelated suites were not run
|
||||
for this narrow test deletion. CI, GitHub duplicate search and reviewer gates
|
||||
remain open. Related prior audit: PR #16075; its files are excluded here.
|
||||
|
||||
Model: OpenAI `gpt-6.1-sol` (GPT-6.1-Sol); context window unavailable. Tool use and
|
||||
code execution supplied the source inspection and proof.
|
||||
|
||||
Original test SHA-256: `92425b672e93810e0de2d21efdcb65c902b1c90926fee2a941322445172a65fe`.
|
||||
Candidate test SHA-256: `1fcad08c3af36e539e7f2c62d706605f65a70c9394026b0beb4ffb8aecc7c867`.
|
||||
Unchanged sibling SHA-256: `ad98a02f6112a21a8975235db6a9dec227020221bf048c8dfcbdbb55c6ce2047`.
|
||||
Restored production-owner SHA-256: `9f29feb6d986f281cbfd849e0152f49cf56e18974c6df1bc801010dcce4c877a`.
|
||||
|
||||
Full commands, source hashes, phase JSON/logs and exact failure stack:
|
||||
`/private/tmp/codex-reconciliation-child-proof/receipt.json` and sibling files.
|
||||
@@ -0,0 +1,216 @@
|
||||
# CompanyExport proof receipt
|
||||
|
||||
Historical proof base `8e955181d8a3776acc86e4662de3c77933231a76`; OpenAI GPT-6.1-Sol.
|
||||
|
||||
Two same-render retirements preserve the complete original check union: empty fidelity-panel absence joins the automatic-preview keeper; initial disabled/unchecked attachment and dimmed task-folder checks join the rich-download keeper before clicks. Existing fidelity API and 3-of-6 file-count assertions remain. Whole-program AST proof confirms all other fixtures, hooks, provider inputs, actions and cases unchanged.
|
||||
|
||||
| Full owner phase | Passed | Failed / skipped | Exit |
|
||||
|---|---:|---:|---:|
|
||||
| Baseline | 13 | 0 / 0 | 0 |
|
||||
| Candidate | 11 | 0 / 0 | 0 |
|
||||
| Full revert | 13 | 0 / 0 | 0 |
|
||||
| Restored candidate | 11 | 0 / 0 | 0 |
|
||||
|
||||
Four independent actual production controls each selected one keeper and exited 1 at its intended guard: render an empty fidelity panel (line 253); enable disabled attachments (317); check disabled attachments (318); stop dimming the excluded tasks directory (319). Each had 0 passing / 1 failing selected case; 10 other cases were filtered out, with no source skips added. Production bytes restored after each; final SHA-256 `52775673ad41a2156e9e3f23016ca7e957fc552930139b2048685a55c10d6d2d`.
|
||||
|
||||
Saving: 2 registered root/provider renders, 14 net test lines (5 added / 19 removed), no measured runtime claim. Initial anchored selector selected zero cases and was rejected by the harness; log/JSON preserved, all controls rerun with corrected unique selectors. Existing React act warnings remain. Diff check passes. No broad suite/typecheck/build for this proof-only proposal. No production changes, branch, commit, push or PR.
|
||||
|
||||
## Inspectable reproduction
|
||||
|
||||
The results above are historical, recorded on 2026-10-13. This documentation repair
|
||||
checks the Git source and mutation hashes; it does not claim fresh test results.
|
||||
Historical raw reports remain local and are not bundled. The relevant failure
|
||||
excerpts and exact executed production edits are included here; no private proof
|
||||
file is needed to reconstruct the checks.
|
||||
|
||||
Run the block from a repository checkout with the public `base` and `head` Git
|
||||
revisions below. Fetch those public PR/revisions first if they are absent.
|
||||
Python 3.12+, Git and Node are required. The UI and Codex recipes also require
|
||||
pnpm 9.15.4 and network access to install dependencies.
|
||||
|
||||
The script uses an isolated snapshot and obtains the candidate test directly
|
||||
from its Git revision. It runs the full baseline and candidate owners, applies
|
||||
each mutation independently, checks the intended failing case, restores exact
|
||||
source bytes in `finally`, and reruns the full candidate. Counts are
|
||||
`[total, passed, failed, skipped-or-filtered]`. Original-owner mutation counts
|
||||
above are historical; this recipe repeats candidate sensitivity checks.
|
||||
Prefix the command with `AUDIT_RECONSTRUCT_ONLY=1` to verify source and mutation
|
||||
hashes without extracting a snapshot, installing dependencies or running tests.
|
||||
|
||||
```sh
|
||||
python3 - <<'PY'
|
||||
import hashlib, io, json, os, re, subprocess, tarfile, tempfile
|
||||
from pathlib import Path
|
||||
|
||||
spec = {'base': '8e955181d8a3776acc86e4662de3c77933231a76',
|
||||
'head': '34270ee5c767a561fe34fe57a6d807d1a9496f70',
|
||||
'owner': 'ui/src/pages/CompanyExport.test.tsx',
|
||||
'kind': 'ui',
|
||||
'hashes': {'ui/src/pages/CompanyExport.test.tsx': '096af584a2f94cd423a59296b6e7af160081e95f6234747573973197f766cb0c',
|
||||
'ui/src/pages/CompanyExport.tsx': '52775673ad41a2156e9e3f23016ca7e957fc552930139b2048685a55c10d6d2d'},
|
||||
'candidate_hash': 'a6cceb2266154c372d9081ec79ca3dcd8e3acb6994e2599bbc98dd11f8988012',
|
||||
'baseline': [13, 13, 0, 0],
|
||||
'candidate': [11, 11, 0, 0],
|
||||
'mutations': [{'name': 'empty-fidelity',
|
||||
'path': 'ui/src/pages/CompanyExport.tsx',
|
||||
'changes': [['{fidelityReport && fidelityReport.warnings.length > 0 && (',
|
||||
'{fidelityReport && (']],
|
||||
'hash': 'a9f8c23c46b994199221719de840292a9c8c2c9ff613e5f4e220441b5c4cd0ea',
|
||||
'counts': [11, 0, 1, 10],
|
||||
'guard': 'loads the no-task export automatically without an interstitial',
|
||||
'message': "AssertionError: expected 'Paperclip exportExporting 1 of 1 file…' not to "
|
||||
"contain 'Not included in this export'",
|
||||
'selector': 'loads the no-task export automatically without an interstitial',
|
||||
'line': 253},
|
||||
{'name': 'attachments-enabled',
|
||||
'path': 'ui/src/pages/CompanyExport.tsx',
|
||||
'changes': [['const disabled = isAttachments && '
|
||||
'!isAttachmentsCategoryEnabled(categories);',
|
||||
'const disabled = false;']],
|
||||
'hash': '0b978fefc8f332f4863d16d8af9a76ebdd2d6916fc3778c588fceee08173a3ae',
|
||||
'counts': [11, 0, 1, 10],
|
||||
'guard': 'keeps task history opt-in, then requests all selected files on download',
|
||||
'message': 'AssertionError: expected false to be true // Object.is equality',
|
||||
'selector': 'keeps task history opt-in, then requests all selected files on download',
|
||||
'line': 317},
|
||||
{'name': 'attachments-checked',
|
||||
'path': 'ui/src/pages/CompanyExport.tsx',
|
||||
'changes': [['const checked = categories[key] && !disabled;',
|
||||
'const checked = isAttachments && disabled ? true : categories[key] && '
|
||||
'!disabled;']],
|
||||
'hash': '966c964b9b8c124cb60c280146619eca379095a89ddb8930420365614a72498d',
|
||||
'counts': [11, 0, 1, 10],
|
||||
'guard': 'keeps task history opt-in, then requests all selected files on download',
|
||||
'message': 'AssertionError: expected true to be false // Object.is equality',
|
||||
'selector': 'keeps task history opt-in, then requests all selected files on download',
|
||||
'line': 318},
|
||||
{'name': 'undimmed-task-folder',
|
||||
'path': 'ui/src/pages/CompanyExport.tsx',
|
||||
'changes': [['if (!anyIncluded) tones[node.path] = "muted";',
|
||||
'if (!anyIncluded && node.path !== "tasks") tones[node.path] = "muted";']],
|
||||
'hash': 'f1f8f968e1ffe2bd26d4158ba86f6639531131bd96d728a0b62811d6f27f71ab',
|
||||
'counts': [11, 0, 1, 10],
|
||||
'guard': 'keeps task history opt-in, then requests all selected files on download',
|
||||
'message': "AssertionError: expected 'group grid w-full grid-cols-(--gtc-3)…' to "
|
||||
"contain 'opacity-50'",
|
||||
'selector': 'keeps task history opt-in, then requests all selected files on download',
|
||||
'line': 319}]}
|
||||
|
||||
def digest(data):
|
||||
return hashlib.sha256(data).hexdigest()
|
||||
|
||||
def blob(rev, path):
|
||||
return subprocess.check_output(["git", "show", rev + ":" + path])
|
||||
|
||||
owner = spec["owner"]
|
||||
original = {p: blob(spec["base"], p) for p in spec["hashes"]}
|
||||
candidate = blob(spec["head"], owner)
|
||||
assert all(digest(b) == spec["hashes"][p] for p, b in original.items())
|
||||
assert digest(candidate) == spec["candidate_hash"]
|
||||
mutants = []
|
||||
for m in spec["mutations"]:
|
||||
text = original[m["path"]].decode()
|
||||
for before, after in m["changes"]:
|
||||
assert text.count(before) == 1, (m["name"], "ambiguous mutation")
|
||||
text = text.replace(before, after)
|
||||
data = text.encode()
|
||||
assert digest(data) == m["hash"], m["name"]
|
||||
mutants.append((m, data))
|
||||
if os.environ.get("AUDIT_RECONSTRUCT_ONLY") == "1":
|
||||
print("Original, candidate and all mutation hashes match historical proof.")
|
||||
raise SystemExit(0)
|
||||
|
||||
archive = subprocess.check_output(["git", "archive", spec["base"]])
|
||||
with tempfile.TemporaryDirectory(prefix="paperclip-audit-") as directory:
|
||||
root = Path(directory)
|
||||
with tarfile.open(fileobj=io.BytesIO(archive)) as tar:
|
||||
tar.extractall(root, filter="data")
|
||||
if spec["kind"] != "tap":
|
||||
assert subprocess.check_output(["pnpm", "--version"], cwd=root, text=True).strip() == "9.15.4"
|
||||
subprocess.run(["pnpm", "install", "--frozen-lockfile"],
|
||||
cwd=root, check=True)
|
||||
|
||||
def run(label, expected, mutation=None):
|
||||
report = root / "audit-report.json"
|
||||
if report.exists():
|
||||
report.unlink()
|
||||
if spec["kind"] == "tap":
|
||||
command = ["node", "--test", "--test-reporter=tap", owner]
|
||||
elif spec["kind"] == "ui":
|
||||
command = ["pnpm", "--filter", "@paperclipai/ui",
|
||||
"exec", "vitest", "run", "src/pages/CompanyExport.test.tsx",
|
||||
"--maxWorkers=1", "--reporter=default", "--reporter=json",
|
||||
"--outputFile.json=" + str(report)]
|
||||
else:
|
||||
command = ["node", "node_modules/vitest/vitest.mjs", "run", "--config",
|
||||
"packages/adapters/codex-local/vitest.config.ts", owner,
|
||||
"--reporter=json", "--outputFile=" + str(report)]
|
||||
if mutation and mutation.get("selector"):
|
||||
command += ["-t", mutation["selector"]]
|
||||
result = subprocess.run(command, cwd=root, capture_output=True, text=True,
|
||||
timeout=180)
|
||||
output = result.stdout + result.stderr
|
||||
print(label, "exit", result.returncode, output)
|
||||
if spec["kind"] == "tap":
|
||||
counts = {k: int(v) for k, v in re.findall(
|
||||
r"^# (tests|pass|fail|skipped) (\d+)$", output, re.M)}
|
||||
actual = [counts[k] for k in ["tests", "pass", "fail", "skipped"]]
|
||||
if mutation:
|
||||
failures = re.findall(
|
||||
r"^not ok \d+ - (.*?)\n(.*?)(?=^(?:ok|not ok) \d+ - |^1\.\.|\Z)",
|
||||
output, re.M | re.S)
|
||||
assert any(name == mutation["guard"] and mutation["message"] in body
|
||||
and "ERR_ASSERTION" in body for name, body in failures), label
|
||||
else:
|
||||
data = json.loads(report.read_text())
|
||||
actual = [data[k] for k in ["numTotalTests", "numPassedTests",
|
||||
"numFailedTests", "numPendingTests"]]
|
||||
if mutation:
|
||||
hits = [a for suite in data["testResults"] for a in suite["assertionResults"]
|
||||
if a["status"] == "failed" and mutation["guard"] in a["fullName"]]
|
||||
assert any(mutation["message"] in msg for a in hits
|
||||
for msg in a["failureMessages"]), label
|
||||
if mutation.get("line"):
|
||||
assert any(f'CompanyExport.test.tsx:{mutation["line"]}:' in msg
|
||||
for a in hits for msg in a["failureMessages"]), label
|
||||
assert actual == expected, (label, actual, expected)
|
||||
assert result.returncode == (1 if mutation else 0), label
|
||||
|
||||
try:
|
||||
run("baseline", spec["baseline"])
|
||||
(root / owner).write_bytes(candidate)
|
||||
run("candidate", spec["candidate"])
|
||||
for m, data in mutants:
|
||||
try:
|
||||
(root / owner).write_bytes(candidate)
|
||||
(root / m["path"]).write_bytes(data)
|
||||
run(m["name"] + "-keeper", m["counts"], m)
|
||||
finally:
|
||||
for path, data in original.items():
|
||||
(root / path).write_bytes(data)
|
||||
assert all((root / p).read_bytes() == b for p, b in original.items())
|
||||
(root / owner).write_bytes(candidate)
|
||||
run("restored-candidate", spec["candidate"])
|
||||
finally:
|
||||
for path, data in original.items():
|
||||
(root / path).write_bytes(data)
|
||||
assert all((root / p).read_bytes() == b for p, b in original.items())
|
||||
PY
|
||||
```
|
||||
|
||||
Recorded intended failure excerpts (fixture path prefixes omitted):
|
||||
|
||||
```text
|
||||
empty-fidelity / loads the no-task export automatically without an interstitial
|
||||
AssertionError: expected 'Paperclip exportExporting 1 of 1 file…' not to contain 'Not included in this export'
|
||||
CompanyExport.test.tsx:253
|
||||
attachments-enabled / keeps task history opt-in, then requests all selected files on download
|
||||
AssertionError: expected false to be true // Object.is equality
|
||||
CompanyExport.test.tsx:317
|
||||
attachments-checked / keeps task history opt-in, then requests all selected files on download
|
||||
AssertionError: expected true to be false // Object.is equality
|
||||
CompanyExport.test.tsx:318
|
||||
undimmed-task-folder / keeps task history opt-in, then requests all selected files on download
|
||||
AssertionError: expected 'group grid w-full grid-cols-(--gtc-3)…' to contain 'opacity-50'
|
||||
CompanyExport.test.tsx:319
|
||||
```
|
||||
@@ -0,0 +1,73 @@
|
||||
# Company UI test consolidation proof
|
||||
|
||||
Proof base: PR #16111 exact head `06c1b2035df44fa03c065ddd69e8bf8df8513b86`. Proof used GPT-6.1-Sol. The changes affect only test files.
|
||||
|
||||
| Owner | Original | Candidate | Full original-file restore | Candidate restored |
|
||||
|---|---:|---:|---:|---:|
|
||||
| `ui/src/pages/CompanyImport.test.tsx` | 29/29 | 28/28 | 29/29 | 28/28 |
|
||||
| `ui/src/pages/CompanyEnvironments.test.tsx` | 32/32 | 31/31 | 32/32 | 31/31 |
|
||||
|
||||
All complete-owner runs exited 0, with no failures or skips. Both production mutations below exited 1 with exactly one failure in the keeper. The mutated production files were restored byte for byte before the final candidate runs. The reduction removes 2 test registrations and 15 net test lines. The isolated runs were about 7 seconds and 4 seconds per owner; this is not a CI timing claim.
|
||||
|
||||
## Reproduce
|
||||
|
||||
Use a clean checkout at the proof base with dependencies installed. Run commands from the repository root.
|
||||
|
||||
```sh
|
||||
pnpm --filter @paperclipai/ui exec vitest run src/pages/CompanyImport.test.tsx --maxWorkers=1
|
||||
pnpm --filter @paperclipai/ui exec vitest run src/pages/CompanyEnvironments.test.tsx --maxWorkers=1
|
||||
```
|
||||
|
||||
Expected original counts: 29 and 32 passing tests. Apply the PR's two test-file changes and rerun the same commands: 28 and 31 passing tests. Restore both complete original test files from the proof-base commit and rerun: 29 and 32 passing. Reapply the candidate changes and rerun: 28 and 31 passing.
|
||||
|
||||
## Production mutation controls
|
||||
|
||||
For CompanyImport, apply the candidate test change, then in `ui/src/pages/CompanyImport.tsx` replace the success-path invalidation below:
|
||||
|
||||
```ts
|
||||
await queryClient.invalidateQueries({ queryKey: queryKeys.companies.all });
|
||||
```
|
||||
|
||||
with:
|
||||
|
||||
```ts
|
||||
await queryClient.invalidateQueries({ queryKey: ["audit-unrelated-company-query"] });
|
||||
```
|
||||
|
||||
Run only the keeper:
|
||||
|
||||
```sh
|
||||
pnpm --filter @paperclipai/ui exec vitest run src/pages/CompanyImport.test.tsx --maxWorkers=1 -t 'submits the import as an async job, then activates selected agents and routines'
|
||||
```
|
||||
|
||||
Expected result: exit 1 at the `invalidateQueries` query-key assertion. The control observed the unrelated key in the real QueryClient call. Restore `CompanyImport.tsx` from the proof-base commit and verify its SHA-256 is `872d67109ab968fada24f126ad92974c5d060f7552dc4e8299a6185d2b87fe6c`.
|
||||
|
||||
For CompanyEnvironments, apply the candidate test change, then in `ui/src/pages/CompanyEnvironments.tsx` replace the Local option:
|
||||
|
||||
```tsx
|
||||
<option value="">Local</option>
|
||||
```
|
||||
|
||||
with:
|
||||
|
||||
```tsx
|
||||
null
|
||||
```
|
||||
|
||||
Run only the keeper:
|
||||
|
||||
```sh
|
||||
pnpm --filter @paperclipai/ui exec vitest run src/pages/CompanyEnvironments.test.tsx --maxWorkers=1 -t 'opens the add-environment form on a standalone page and closes it on cancel'
|
||||
```
|
||||
|
||||
Expected result: exit 1 at the migrated `Local` option assertion. Restore `CompanyEnvironments.tsx` from the proof-base commit and verify its SHA-256 is `871d93af7394090ccdb6ffaaa518c7462055ffb75766e6b9736afdd34e18884b`.
|
||||
|
||||
After both restores, rerun the complete candidate-owner commands. They must pass 28/28 and 31/31. Keep the candidate changes in the two test files; do not leave either production mutation applied.
|
||||
|
||||
## Retained behavior
|
||||
|
||||
CompanyImport retains the full async import and activation assertions. The keeper adds a QueryClient invalidation spy and confirms the companies list is invalidated before activation. Its `finally` path restores the spy.
|
||||
|
||||
CompanyEnvironments moves the implicit Local-option assertion into the existing add-environment scenario after the same initial render and React flush, before opening Add. The same scenario retains the form and cancel assertions.
|
||||
|
||||
The proof also checked that retained test names, fixtures, provider state, actions, hooks, and assertions were unchanged beyond these migrations. There are no skips or production changes in this pull request.
|
||||
@@ -0,0 +1,29 @@
|
||||
# DB client test migration-pass audit
|
||||
|
||||
This test-only change removes 15 redundant initial `applyPendingMigrations(connectionString)` calls from `packages/db/src/client.test.ts`. Every test declaration and assertion stays unchanged. No production code, migration, import, or fixture helper changes.
|
||||
|
||||
## Why the calls are redundant
|
||||
|
||||
`createTempDatabase()` awaits `startEmbeddedPostgresTestDatabase()` before returning its connection string. The shared fixture awaits `ensurePostgresDatabase()` and `applyPendingMigrations()` before returning on both the fresh and template paths. Each removed call immediately followed `await createTempDatabase()`, with no intervening schema, migration-journal, or fixture-data mutation. It therefore inspected the same fully migrated database again.
|
||||
|
||||
For this fixture's hash-based migration journal, the repeated pass enters `inspectMigrations()`, opens a one-connection DB utility pool, and loads the applied hashes. `mapHashesToMigrationFiles()` reads and SHA-256 hashes every migration SQL file. The directory contains 334 SQL files at this revision. Removing 15 such passes avoids 15 × 334 = **5,010 migration SQL file reads and hashes**, plus **15 DB utility pool passes**. These are operation counts derived from the source and migration directory, not measured seconds or a CI speedup estimate. The fixture's required migration pass remains.
|
||||
|
||||
## Exact removal boundary
|
||||
|
||||
The removed calls were at original lines 204, 274, 327, 371, 401, 473, 567, 633, 699, 773, 877, 1010, 1406, 1983, and 2011. The import stays used by the replay tests.
|
||||
|
||||
All migration calls after journal or schema mutation remain, including the original calls at lines 191, 226, 295, 358, 433, 527, 598, 664, 735, 811, 971, 1045, 1297, 1384, 1510, 1604, 1930, 1998, and 2065. These preserve older-clone upgrades; renumbered recovery replay; inserted earlier migrations; 0044, 0046, 0047, 0048, 0050, and 0059 replay; built-in managed-resource history; 0134 inbox archives; all three 0135 repair/no-op passes; run-responsible-user repair; native persistence/status-versioning replay; provider-trace idempotence; and retired-model-profile cleanup. No replay call is removed from the board-key uniqueness test, which has no later mutation requiring migration.
|
||||
|
||||
The fixture-helper tests remain unchanged, including `publishes a complete template and starts suites from a copy of it` and `runs the fresh initdb path when PAPERCLIP_TEST_POSTGRES_TEMPLATE=0`. Both assert that the returned database reports `upToDate`.
|
||||
|
||||
## Verification
|
||||
|
||||
```sh
|
||||
node_modules/.bin/vitest run --project @paperclipai/db packages/db/src/client.test.ts packages/db/src/test-embedded-postgres.test.ts
|
||||
```
|
||||
|
||||
Complete owner replay: **2 files passed, 35 tests passed, 0 failed, 0 skipped; 26.77 seconds**. Real embedded PostgreSQL executed, including the fresh and template fixture-owner tests. The first sandboxed invocation encountered `listen EPERM` on localhost and was interrupted; the successful identical command ran with local socket access. No baseline timing comparison was run.
|
||||
|
||||
`git diff --check` passes. A byte-level reconstruction against HEAD confirms that the client test file retains every original line except the 15 specified call lines. It retains 19 `applyPendingMigrations(connectionString)` references and the corresponding import.
|
||||
|
||||
Risk: these tests now rely directly on the fixture's existing fully-migrated return contract. The fresh/template owner tests cover that contract. Mutation and idempotence coverage remains in the same client suite.
|
||||
@@ -0,0 +1,112 @@
|
||||
{
|
||||
"auditBase": "e868e6645ce0d598d756d3458f0b3d71afd6db4a",
|
||||
"historicalWeightsMs": {
|
||||
"selection": 1173,
|
||||
"phase6": 19600,
|
||||
"finalizer": 19882
|
||||
},
|
||||
"owners": {
|
||||
"runtimeMode": 27,
|
||||
"evidenceClassifier": 4,
|
||||
"controlPlanePort": 34
|
||||
},
|
||||
"removedAliasExecutions": 99,
|
||||
"restoration": {
|
||||
"owner": "server/src/services/native-runtime/paperclip-control-plane-port.ts",
|
||||
"originalSha256": "621beee8a451e9cab4fc09f886bfb4d95512c1433f82b7f9cbd3ea83fd2f3d0c",
|
||||
"restoredSha256": "621beee8a451e9cab4fc09f886bfb4d95512c1433f82b7f9cbd3ea83fd2f3d0c",
|
||||
"restored": true
|
||||
},
|
||||
"runs": {
|
||||
"execution-audit-pure-baseline": {
|
||||
"path": "/private/tmp/execution-audit-pure-baseline.json",
|
||||
"sha256": "1b5a7f42848ccd40eabbe409e8eb6331f0f41f70c12c54c11715cc29402148fb",
|
||||
"passed": 31,
|
||||
"failed": 0,
|
||||
"pending": 0,
|
||||
"success": true
|
||||
},
|
||||
"execution-audit-port-baseline": {
|
||||
"path": "/private/tmp/execution-audit-port-baseline.json",
|
||||
"sha256": "9976aed11c8310e5c7245565413b1b4582367b8ec072006b79e05084c6c5e3c5",
|
||||
"passed": 0,
|
||||
"failed": 0,
|
||||
"pending": 34,
|
||||
"success": false
|
||||
},
|
||||
"execution-audit-port-baseline-repro": {
|
||||
"path": "/private/tmp/execution-audit-port-baseline-repro.json",
|
||||
"sha256": "ea16340d52952745b68ab8050e3c7406a6d61e1aaf142e1705a64066259b9e93",
|
||||
"passed": 0,
|
||||
"failed": 0,
|
||||
"pending": 34,
|
||||
"success": false
|
||||
},
|
||||
"execution-audit-port-baseline-repaired": {
|
||||
"path": "/private/tmp/execution-audit-port-baseline-repaired.json",
|
||||
"sha256": "cb3cd844a49d88dd762630a0914817ac389fbde89370b2917b21c3d5e4a1ad73",
|
||||
"passed": 34,
|
||||
"failed": 0,
|
||||
"pending": 0,
|
||||
"success": true
|
||||
},
|
||||
"execution-audit-selection-replay": {
|
||||
"path": "/private/tmp/execution-audit-selection-replay.json",
|
||||
"sha256": "96935cbb6530793b848728372233281d7945e0d6634ad19faa177ef518c3aefb",
|
||||
"passed": 54,
|
||||
"failed": 0,
|
||||
"pending": 0,
|
||||
"success": true
|
||||
},
|
||||
"execution-audit-port-mutation": {
|
||||
"path": "/private/tmp/execution-audit-port-mutation.json",
|
||||
"sha256": "e9fcf577361e22373a9f07be42e53e5690290c57a630029ed78e7e9978da6cd5",
|
||||
"passed": 0,
|
||||
"failed": 1,
|
||||
"pending": 33,
|
||||
"success": false
|
||||
},
|
||||
"execution-audit-port-control": {
|
||||
"path": "/private/tmp/execution-audit-port-control.json",
|
||||
"sha256": "59f030337cea965a4a135a62f0fe8315ed52f0bffd2ed5311040094d4517049e",
|
||||
"passed": 1,
|
||||
"failed": 0,
|
||||
"pending": 33,
|
||||
"success": true
|
||||
}
|
||||
},
|
||||
"deliveryBase": "770cc3be7e294d606d83599c6f6a3232d47d4c70",
|
||||
"branch": "codex/prune-native-acceptance-wrappers",
|
||||
"candidate": {
|
||||
"jsonSha256": "d7fe27f05c8ea33682a69f336e196020502cb42ae04f4717d9c8ffa7ef18c31c",
|
||||
"passed": 65,
|
||||
"failed": 0,
|
||||
"pending": 0
|
||||
},
|
||||
"retainedOwnerSha256": {
|
||||
"server/src/services/native-runtime/runtime-mode.test.ts": "c32e6b5276fc30a78f5f91ad7c9b46438d4b08917a3d933bbb1d991ef2b4d7e1",
|
||||
"server/src/services/native-runtime/evidence-classifier.test.ts": "4567ab0fa44b311d83110c1fe7a5d6051cf099131db019f1024858cc3c6e7d0c",
|
||||
"server/src/services/native-runtime/paperclip-control-plane-port.test.ts": "d236a5239fd4c7e15447740b04d160a51d268d555c7fb43c42e99cca4c417985"
|
||||
},
|
||||
"mutationFailure": {
|
||||
"case": "revalidates every persisted native binding before open and completion",
|
||||
"assertionLine": 1131,
|
||||
"message": "promise resolved \"undefined\" instead of rejecting",
|
||||
"selectedFailed": 1,
|
||||
"filteredPending": 33
|
||||
},
|
||||
"defaultShardSelection": {
|
||||
"shards": 12,
|
||||
"selectedFiles": 886,
|
||||
"uniqueFiles": 886,
|
||||
"eachOwnerCount": 1,
|
||||
"retiredAliasCount": 0,
|
||||
"retainedInputAliasCount": 1
|
||||
},
|
||||
"stockShardTests": {
|
||||
"passed": 29,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"logSha256": "bd0026448f3025cc8166d9ef02e8c90252e66da45af693717ef744fdbb7e0576"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
# Execution wrapper test audit — 2026-10-13
|
||||
|
||||
Remove three import-only acceptance aliases while retaining their complete production-boundary owners. This retires **99 duplicate case registrations and nine test lines**, with **zero production behavior changes**. Complete retained-owner baselines and the final candidate each pass **65/65 cases**, with no failures or skips.
|
||||
|
||||
Delivery base: `770cc3be7e294d606d83599c6f6a3232d47d4c70`, the merged root after #16188. Qualification began at `e868e6645ce0d598d756d3458f0b3d71afd6db4a`; all three owners, the mutated production owner, and affected ownership references are byte-identical between those bases. Followed the OpenClaw [test-audit skill](https://github.com/openclaw/openclaw/blob/main/.agents/skills/test-audit/SKILL.md) and its candidate-evidence and retention rules.
|
||||
|
||||
## Retired aliases and retained contracts
|
||||
|
||||
| Retired server acceptance alias | Complete retained owner | Repeated cases | Removed test lines | Historical CI weight |
|
||||
|---|---|---:|---:|---:|
|
||||
| `heartbeat-native-runner-selection.test.ts` | `services/native-runtime/runtime-mode.test.ts` | 27 | 2 | 1,173 ms |
|
||||
| `native-runner-phase6.integration.test.ts` | `services/native-runtime/paperclip-control-plane-port.test.ts` | 34 | 3 | 19,600 ms |
|
||||
| `native-run-finalizer.test.ts` | `services/native-runtime/paperclip-control-plane-port.test.ts` plus `services/native-runtime/evidence-classifier.test.ts` | 38 | 4 | 19,882 ms |
|
||||
|
||||
Every retired executable line imports one of those test modules. There are no alias-owned assertions, fixtures, mocks, hooks, filters, configuration, or entry-point actions. All aliases originated unchanged in `25cf079ec5` (#12591, 2026-08-31), when server Vitest already included the colocated owners. The shared `src/**/*.test.ts` configuration, setup file, isolated forks, and default server walker execute the same owners. An actual current-Vitest run of runtime-mode plus its alias passes 54/54, demonstrating the duplicate registration.
|
||||
|
||||
Retain every runtime-selection, compatibility, persisted binding, authorization, redaction, event/replay, result, governance, review, transactional ordering, rollback, workspace-failure, and durable-evidence assertion in the three owners. Their bytes, table rows, timers, awaits, and budgets are unchanged. Independent parent review confirmed that the six-file cleanup removes only these import aliases and redirects the affected pointers.
|
||||
|
||||
Retain `native-runner-input-boundary.test.ts`: it imports a Runner package suite omitted from the root default project list. Deleting that superficially similar alias would remove root-suite input-contract coverage. Prior audit receipts and excluded adapter, native-session, recovery, workspace-runtime, UI, and E2E areas were not revisited.
|
||||
|
||||
The protocol-coverage generator and generated artifact now name the actual runtime-mode owner. The standalone-thin documentation invokes the three canonical owners directly and removes retired aliases from its file inventories. These labels carry no separate executable matrix signal; no acceptance requirement, source assertion, CI route, or production seam changes.
|
||||
|
||||
## Qualification and reversal
|
||||
|
||||
- Baseline: runtime-mode 27/27, evidence-classifier 4/4, and the complete real-Postgres control-plane owner 34/34. Final candidate: the same three files, 65/65, zero failures/skips.
|
||||
- Mutation: bypass only the persisted `run.nativeIssueId === this.#binding.issueId` comparison in `PaperclipControlPlanePort`. The retained `revalidates every persisted native binding before open and completion` fails at its rejection assertion (line 1131): the first corrupted task-binding open resolves `undefined` instead of rejecting. Setup completed; this was neither a timeout nor a harness failure.
|
||||
- Reversal: restore the production owner byte for byte, then the exact selected guard passes. Its 33 excluded cases are intentional name-filter skips, not a complete-file control claim. Restoration SHA-256: `621beee8a451e9cab4fc09f886bfb4d95512c1433f82b7f9cbd3ea83fd2f3d0c`.
|
||||
- Default routing: 886 unique general-server files across all 12 stock shards; each retained owner appears exactly once, retired aliases zero times, and the required package-input alias once. Stock shard-routing tests pass 29/29.
|
||||
- Runner `build:typescript`, generated protocol-coverage `--check`, generator syntax check, owner byte comparisons, and `git diff --check` pass.
|
||||
|
||||
Focused candidate command:
|
||||
|
||||
```sh
|
||||
pnpm --filter @paperclipai/server exec vitest run \
|
||||
src/services/native-runtime/runtime-mode.test.ts \
|
||||
src/services/native-runtime/evidence-classifier.test.ts \
|
||||
src/services/native-runtime/paperclip-control-plane-port.test.ts
|
||||
```
|
||||
|
||||
## Cost and limits
|
||||
|
||||
The **40.655 seconds** total above is historical raw suite weight from `scripts/general-server-shard-durations.json`, averaged from PR CI runs 38076844891 and 38076972444 (2026-10-10). It is not a fresh causal speed measurement or a prediction of critical-path job savings. No timing claim comes from removed line counts. The successful full port baseline took 16.472 seconds of test time (25.84-second invocation); the final three-owner candidate took 26.08 seconds total. Their scopes and host state differ, so they are not an A/B speed comparison.
|
||||
|
||||
Two initial database attempts failed before any assertions because the isolated `--ignore-scripts` install omitted Postgres dylib symlinks. The dependency's standard hydration script repaired that isolated setup; subsequent real-DB baseline, mutation, reversal, and candidate runs reached their intended assertions. Read-only shared-memory inventories showed 29 then 30 allocations against a 32-entry limit. No unrelated process was inspected, stopped, or changed. These failed setup attempts are excluded from the passing counts.
|
||||
|
||||
This is complete affected-owner proof. A combined execution of all retired aliases was not repeated; doing so would replay the expensive unchanged database owner. Vitest's combined `list` collection reported no-suite errors on import aliases because it reuses module registrations; collection is not used as runtime preservation proof. No complete repository typecheck, default suite, full build, Rust qualification, browser suite, or fresh remote CI pass was obtained for this local branch. Their absence is not represented as a full repository pass. Publication follows the parent's sequential stack disposition.
|
||||
|
||||
[Compact controls and provenance](2026-10-13-execution-wrapper-test-audit-controls.json) retain source/run hashes, counts, and the intended mutation failure. Raw logs and run JSON remain temporary local audit evidence; digests identify them but do not make them durable payloads.
|
||||
@@ -0,0 +1,74 @@
|
||||
# Proven Grok stale-promotion cleanup consolidation
|
||||
|
||||
Proof base: #16106 exact head 397459400c6e7b18b462dcac3d8886b390ca8e8c. Supplied patch SHA256 verified as 06b3f1bdafc81bc0da4b47d18d9348101cb94a647de2da269bfe4903b73f6a3a. Original test, promotion production module, decision wrapper/CJS, home resolver and directory lock source match exact-head blobs. Isolated temporary snapshot only; serial full-owner runs; no shared checkout edits, commits, pushes or PR.
|
||||
|
||||
Result: PROVEN. Owner packages/adapters/grok-local/src/server/adapter-auth-promotion.test.ts shrinks 658 -> 633 lines (25 net); cases 30 -> 29; one fixture/two promotion calls retired. The production call chain also removes one real local Node predicate child: the empty-home first promotion seeds in-process, while the second same-identity promotion calls writeSameIdentityCredentialIfFresher → decideGrokAuthMerge → execFile("node", [grok-auth-merge-decision.cjs,...]). This is a source-proven call delta, not a measured child counter or provider run. Supplied static map's zero-subprocess statement overlooked that local predicate. No wall-time claim.
|
||||
|
||||
Keeper `keeps the home when the login is older than the existing same-identity credential` gains the retired case's actual company-home readdir equality. Retire `leaves no staged temporary file in the company home after a kept (not-fresher) outcome`.
|
||||
|
||||
Both original cases allocate the same root/env, promote UUID_A marker fresher expiry June2026 into companyA, then promote marker staler expiry January2026, user initiated=true, readiness=ready, soleOwner and noopLog. Keeper retains exact kept outcome and persisted fresher-token receipt, then checks actual entries===auth.json. Static Babel proof reports identical fixture/action prefixes after location/comment removal; runtime uses real scoped persistence, canonical directory lock and real decision predicate. Tied-expiry, success cleanup, redaction, user/sole-owner gates and cross-company cases remain untouched. No ownership or expected value changes.
|
||||
|
||||
| Complete-owner phase | Cases | Pass | Fail | Exit |
|
||||
|---|---:|---:|---:|---:|
|
||||
| baseline | 30 | 30 | 0 | 0 |
|
||||
| candidate | 29 | 29 | 0 | 0 |
|
||||
| reverted-owner | 30 | 30 | 0 | 0 |
|
||||
| kept-temp-leak-original | 30 | 29 | 1 | 1 |
|
||||
| kept-temp-leak-keeper | 29 | 28 | 1 | 1 |
|
||||
| restored-candidate | 29 | 29 | 0 | 0 |
|
||||
| integrated-stack | 29 | 29 | 0 | 0 |
|
||||
|
||||
Every run has zero pending/todo/skipped cases. Reverted-owner is a complete positive run of the exact original source before mutation, not only a source copy.
|
||||
|
||||
## Actual production mutation
|
||||
|
||||
Remove only `await rm(stagedTempPath, { force: true }).catch(() => undefined);` from writeSameIdentityCredentialIfFresher's finally. Leave the separate initial-publish writeAuthFileAtomically cleanup, handle close, decision predicate and rename intact. Actual stale same-identity keep outcome leaks .auth-PID-UUID.tmp alongside auth.json. Original retired case and keeper each fail their real readdir equality directly; each complete owner has exactly one failure. Keeper still observes kept and the correct persisted fresher credential before failing cleanup equality, so the mutation does not substitute a wrong identity/status outcome as proof.
|
||||
|
||||
Verbose original/keeper logs show the actual randomly generated temp filename as a received directory entry; no synthetic filename or expected list is produced by the mutation. Initial JSON-only original-control output abbreviated the received array, so its evidence harness declined to qualify the filename check. Source was restored and the sequence repeated with verbose+JSON reporters; accepted controls show actual leaked entries. The initial positive/control report copies remain in initial-json-reporter-attempt/; no production/assertion modification was used to expose a different outcome.
|
||||
|
||||
Production/test restore occurs in finally and is byte/hash-verified. Restored full candidate passes 29/29; all source finally returns to exact #16106 originals. Test afterEach removes its fake credential fixture roots, including leaked files; async predicate execFile awaits/reaps its child. No real provider, credentials, global instance home or other company was touched.
|
||||
|
||||
## Hashes and integrated stack
|
||||
|
||||
- Original test SHA256: 6925e2b73d52a02ada9457122a2d2262237b937028840443a4aaf38a8f2a2291
|
||||
- Proven candidate test SHA256: 653f85a7b4933e2db534155f3cfbdde1599e0c063b973d490125f58832b7b222
|
||||
- Original/restored promotion production SHA256: aa21740457ceef46e6cddf76dc640f1ed9056e16337ca8ed6def8a2b046e1543
|
||||
|
||||
All four proven shard/provisioning/Codex/Grok patches pass git apply --check and apply together without conflict on exact #16106. Integrated Grok owner passes 29/29 with all four patches present; integrated-receipt.json pins their test hashes and report digest. All four tests restore to exact #16106 bytes afterwards. Other three owners are not claimed rerun in that combined state.
|
||||
|
||||
Use checked-in root Vitest projects config (Grok has no separate config), exact full owner filter, same isolated workspace-source links and immutable third-party dependency graph as the Codex proof. Five additional root third-party links needed for root config loading are recorded in base-hashes.json; no shared workspace source links. No custom mocked resolver, provider, decision or credential comparison replaces production behavior.
|
||||
|
||||
## Checkout reproduction
|
||||
|
||||
Use a fresh checkout at the exact proof base above with repository dependencies installed through the pinned pnpm version. All commands below run from the repository root. After the baseline, fetch the reviewed branch and generate the candidate-only patch: `git fetch origin codex/test-audit-grok-auth-promotion && git diff 397459400c6e7b18b462dcac3d8886b390ca8e8c FETCH_HEAD -- packages/adapters/grok-local/src/server/adapter-auth-promotion.test.ts > /tmp/grok-candidate.patch`. Check and apply it with `git apply --check /tmp/grok-candidate.patch && git apply /tmp/grok-candidate.patch`.
|
||||
|
||||
```sh
|
||||
node node_modules/vitest/vitest.mjs run packages/adapters/grok-local/src/server/adapter-auth-promotion.test.ts --reporter=verbose
|
||||
```
|
||||
|
||||
Expected baseline: 30 passing cases. Apply `/tmp/grok-candidate.patch`, then run the same command: 29 passing cases. Restore the original test from `397459400c6e7b18b462dcac3d8886b390ca8e8c` and rerun the same command: 30 passing cases.
|
||||
|
||||
With the original test restored, execute this exact production mutation:
|
||||
|
||||
```python
|
||||
from pathlib import Path
|
||||
|
||||
owner = Path("packages/adapters/grok-local/src/server/adapter-auth-promotion.ts")
|
||||
source = owner.read_text()
|
||||
start = source.index("async function writeSameIdentityCredentialIfFresher(")
|
||||
end = source.index("/**\n * Promotes a Grok", start)
|
||||
section = source[start:end]
|
||||
cleanup = " await rm(stagedTempPath, { force: true }).catch(() => undefined);"
|
||||
assert section.count(cleanup) == 1
|
||||
owner.write_text(source[:start] + section.replace(cleanup, "") + source[end:])
|
||||
```
|
||||
|
||||
Run the same full-owner test command. Expected original control: 29 passing and one failure at `leaves no staged temporary file in the company home after a kept (not-fresher) outcome`; verbose diff shows actual `.auth-<pid>-<uuid>.tmp` and `auth.json` versus the fixed expected `["auth.json"]`.
|
||||
|
||||
Apply `/tmp/grok-candidate.patch` and run the same command under unchanged mutated production. Expected keeper control: 28 passing and one failure at `keeps the home when the login is older than the existing same-identity credential`, with the same actual-directory mismatch.
|
||||
|
||||
Always restore `packages/adapters/grok-local/src/server/adapter-auth-promotion.ts` from the exact proof-base commit in a finally/trap cleanup, even when either deliberately failing command exits 1. Leave the candidate test applied and rerun the same full-owner command: 29 passing cases. Confirm restored production SHA256 equals the value above. The mutation intentionally changes only the second writer's cleanup line; removing the first writer's cleanup or its handle-close line is a different control and must not be substituted.
|
||||
|
||||
For combined integration, apply the other three proven test patches plus this Grok patch to a fresh exact #16106 checkout, require each `git apply --check` to succeed, and run the same full Grok-owner command: 29 passing. No production mutation remains during this positive check.
|
||||
|
||||
The candidate patch is reproducible from the exact proof base and reviewed branch with the fetch/diff command above. Detailed raw phase logs and JSON remain in the original isolated proof workspace and are not claimed as checked-in deliverables. The mutation and restore steps below are fully specified. No broader typecheck/build/default-suite success claim.
|
||||
@@ -0,0 +1,38 @@
|
||||
# Interaction audience duplicate-row audit — 2026-10-13
|
||||
|
||||
## Scope and decision
|
||||
|
||||
Collapse the five-row `it.each` in
|
||||
`server/src/services/issue-thread-interaction-resolution.test.ts` into one test.
|
||||
Four expanded test invocations and six net test lines are removed.
|
||||
|
||||
## Retained coverage
|
||||
|
||||
Each former row only supplied an interaction-kind name to the test title.
|
||||
The callback accepted no row argument. Every invocation supplied the same
|
||||
`agent` actor and the same fresh `interaction()` fixture to
|
||||
`evaluateIssueThreadInteractionResolverAudience`, then checked the same
|
||||
`allowed: true`, `effectiveResolverPolicy: "anyone"`, and `reason: "allow_anyone"`
|
||||
result. The retained test preserves that entire assertion.
|
||||
|
||||
The evaluator's input contract has no interaction-kind property, and its
|
||||
implementation evaluates actor identity, creator/run attribution, addressee,
|
||||
resolver policy, and additional restrictions. The removed names could never
|
||||
select different behavior. The fixture creates a plain object; neither the
|
||||
test nor the evaluator mutates shared state or performs external operations.
|
||||
This file has no per-row hooks or mocks.
|
||||
|
||||
Keep the separate two-row `not_creator` test: its rows supply different creator
|
||||
agent and source-run values and exercise independent exclusion conditions.
|
||||
All other audience, governance, and attention assertions remain unchanged.
|
||||
|
||||
## Validation and limits
|
||||
|
||||
Static review confirmed identical inputs and assertions and no row-specific
|
||||
side effects. Supervisor validation passed the complete owner suite: **12/12**
|
||||
in 1.23 seconds. No production files changed. This is a small reduction in
|
||||
redundant test invocations; no measured CI saving is claimed.
|
||||
|
||||
## Authorship
|
||||
|
||||
OpenAI `gpt-6.1-sol` audit worker, supervised as part of the test-removal campaign.
|
||||
@@ -0,0 +1,20 @@
|
||||
# Interaction route duplicate boundaries test audit — 2026-10-13
|
||||
|
||||
Status: candidate consolidation awaiting focused validation. Based on the clean PR stack at `ec4124ec76`. Owners: `issue-thread-interaction-routes.test.ts` and `interaction-resolution-cross-issue-cap-postgres.test.ts`. Production code is unchanged.
|
||||
|
||||
## Removed executions and retained proof
|
||||
|
||||
| Removed declaration | Retained keeper and transferred assertions |
|
||||
| --- | --- |
|
||||
| `allows the creator agent and creating run under anyone` | The existing five-kind `lets the creator and same run resolve $kind through anyone` matrix already uses the same creator agent, creating run, open policy, assigned issue, and successful HTTP boundary. Its service assertion now checks interaction ID, request body, and authenticated `agentId`/`runId` for every kind. |
|
||||
| Four-row `fails a capped run closed on cross-issue $route with no interaction effect` | The real-routes/real-Postgres four-endpoint cap matrix checks the same 429 code, cap, count, enforcement mode and redaction, plus persisted pending interaction, no child task, no wake, and exactly the rejection activity. It now also checks actionable `Try this:` copy and rejection receipt `kind: interaction_resolution` / `allowed: false`. |
|
||||
| `does not charge a same-issue resolution even past the cap` | The Postgres `leaves same-issue and board resolutions outside the counter` keeper seeds a fully spent run, resolves a same-issue interaction successfully, and verifies the observation count stays at the cap and the rejected count stays zero. |
|
||||
| `leaves board resolutions outside the per-run counter` | The same Postgres keeper resolves a board request on a different issue successfully while preserving both persisted counter totals. |
|
||||
|
||||
The four positive cross-issue route wiring cases remain: each of `accept`, `reject`, `respond`, and `verdicts` must dispatch its own service exactly once and write one shared observation with source/target issue IDs. Postgres currently proves positive charging through `respond`; it therefore does not replace the other positive route wiring cases. Creator/run exclusion, addressed-agent authorization, human-only policy, trust/watchdog gates, native delivery, governed actions, interaction effects, and all remaining route cases remain.
|
||||
|
||||
## Savings and validation
|
||||
|
||||
Four declarations and seven expanded test executions are removed. The mocked route file changes from 3,404 to 3,295 lines (68 to 64 declarations); the Postgres file gains five net lines. Test files total **104 fewer lines** (12 inserted, 116 deleted). Seven repeated route requests and their per-test reset/import setup disappear. No production lines are removed. No wall-clock or CI saving is claimed without a comparable timing run.
|
||||
|
||||
Static review confirmed that the three dispatched service methods accept the asserted `(issue, interactionId, body, actor)` arguments. `git diff --check` passes. Supervisor validation passed both complete owner suites serially: route suite **79/79** in 43.41 seconds; real embedded-Postgres cap suite **7/7** in 15.63 seconds. The PostgreSQL suite ran (not skipped), including each capped endpoint and persisted no-effect checks. No mutation validation or runtime savings claim is made.
|
||||
@@ -0,0 +1,56 @@
|
||||
# Issue update/comment wake-up test audit — 2026-10-13
|
||||
|
||||
## Scope and baseline
|
||||
|
||||
Owned file: `server/src/__tests__/issue-update-comment-wakeup-routes.test.ts`.
|
||||
Worktree: `/private/tmp/paperclip-test-audit-pr-stack`.
|
||||
Baseline HEAD: `9b4d0cd872ca1fc897f320cb181fc060f0bd5bf1` on
|
||||
`codex/test-audit-r13-db-migration-passes`. The owned file is byte-identical
|
||||
at `codex/test-audit-r15-onboarding-duplicates` (`568ba003a559f6a3527c36b715bbf521648518d0`).
|
||||
The coordinator authorized proceeding on the shared checkout without switching branches.
|
||||
|
||||
## Candidate and retained owners
|
||||
|
||||
Delete the standalone own-run top-level comment no-wake case. The retained
|
||||
`keeps $method mentions as context for $scenario` matrix's POST
|
||||
`assignee_comment` case has the same run-authenticated actor, running source
|
||||
run, agent assignee, and in-progress status, plus an explicitly mentioned
|
||||
second agent. It checks successful comment persistence and zero wake-ups;
|
||||
the PATCH counterpart preserves the other route boundary.
|
||||
|
||||
Delete the standalone plain-text agent-name human-owned comment no-wake case.
|
||||
The matrix's POST/PATCH `human_owned` cases preserve the null agent assignee,
|
||||
board user owner, in-progress status, successful comment persistence, and zero
|
||||
wake-ups with a stronger explicit agent mention. The route no longer calls
|
||||
`findMentionedAgents`; the plain-text fixture cannot select a distinct
|
||||
mention-dispatch branch. The matrix also checks updates stay on the original issue.
|
||||
|
||||
No other assertions or fixtures are removed. Retained boundaries include
|
||||
POST/PATCH inherited pause rejection before mutations; done/cancelled assignment
|
||||
suppression; reopening with/without reassignment; normal/external assignment and
|
||||
comment wake context; shared transaction identity and rollback; interrupt agent
|
||||
handoff versus human handoff; structured-goal deferral and invalid status change;
|
||||
PATCH comment-only wakes; Slack session preservation across reopen; explicit resume
|
||||
from a completed run; review-path consumption; self/board/human/unassigned/blocked/
|
||||
done/closing mention scenarios. Response-before-wake waits remain unchanged.
|
||||
|
||||
## Exact reduction
|
||||
|
||||
- Test declarations: 17 → 15.
|
||||
- Expanded cases: 36 → 34 (the 15-case mention matrix stays intact).
|
||||
- Test file lines: 898 → 841.
|
||||
- Test diff: 0 additions, 57 deletions, net −57 lines.
|
||||
- The prior approximate 61-line estimate was not used as a reduction target.
|
||||
|
||||
## Verification
|
||||
|
||||
Owner suite: **34/34 passed**, one file, 27.93 seconds (start 08:37:13). Exact PR-branch command from the repository root:
|
||||
`node_modules/.bin/vitest run --project @paperclipai/server server/src/__tests__/issue-update-comment-wakeup-routes.test.ts --silent=true`.
|
||||
`git diff --check` passed. Mock-backed external sync/sandbox cleanup warnings remain
|
||||
non-failing; no warning-related fixture edits were made.
|
||||
|
||||
Sandbox execution reached all 34 cases but
|
||||
could not bind Supertest's TCP listener (`listen EPERM`); this is an environment
|
||||
failure before route assertions. Rerun outside the sandbox uses the existing
|
||||
installed Vitest directly because pnpm's version switch could not fetch registry
|
||||
signatures. No production source, other tests, staging, commits, or branch changes.
|
||||
@@ -0,0 +1,33 @@
|
||||
# Issue work-product attribution test audit — 2026-10-13
|
||||
|
||||
## Change and remaining proof
|
||||
|
||||
Remove the success-only `stores the authenticated agent run id when creating work products` case from `server/src/__tests__/issue-agent-mutation-ownership-routes.test.ts`. It POSTed an artifact with omitted `createdByRunId` and asserted that the service received the authenticated run ID.
|
||||
|
||||
The retained `adds the authenticated run diff summary to PR work products` case exercises the same route with omitted attribution. It asserts the same `createdByRunId: ownerRunId`, plus the authenticated run's diff lookup and metadata. Forged create/update run attribution and foreign-company board attribution cases also remain.
|
||||
|
||||
The route's `resolveWorkProductCreatedByRunId` helper takes no work-product type. The POST route assigns `createInput.createdByRunId` unconditionally before type-specific metadata enrichment. The removed case used provider `test`, so it did not exercise the separate Paperclip artifact attachment metadata path. The service persists attribution generically across work-product types.
|
||||
|
||||
## Audit scope and evidence
|
||||
|
||||
Read all 83 original declarations, including the human self-handoff cases added in #16082. Before removal, the suite had 64 plain `it` declarations and 19 `it.each` declarations. After removal, it has 63 plain declarations and 19 `it.each` declarations; the 19 tables expand to 79 rows, for 142 runtime cases. Retain all other declarations: their route registrations, actor classes, recovery authority, admission, workspace defaults, or observable ordering differ. In particular, independently registered write routes must each preserve their authorization gate, even when they share a helper.
|
||||
|
||||
Reviewed the owning route attribution helper and POST handler, work-product service persistence and metadata helper, sibling `work-products.test.ts`, production route mounting, CLI work-product create/update commands, board API calls, test helper and Vitest configuration, CI selection, and relevant history. The removed case originated in `86b0fe7d01` on June 5; the stronger keeper arrived in `87d05e194b` (#12717) on September 2.
|
||||
|
||||
The suite already hoists its module graph (#13524). Its historical 50,945ms shard weight comes from September 12 and includes isolated process startup, imports, collection, tests, and shutdown. It is not a runtime savings estimate. CI still selects the file through the serialized route/authz matcher; PR and release workflows invoke `pnpm test:run:serialized` with shard parameters.
|
||||
|
||||
## Savings
|
||||
|
||||
- Test code: 16 lines removed, including its separator.
|
||||
- Declarations: 83 → 82; expanded cases: 143 → 142.
|
||||
- Requests: one fewer HTTP request per owner-suite run.
|
||||
- Production and shared support: zero lines changed.
|
||||
- Runtime savings: not measured.
|
||||
|
||||
## Validation
|
||||
|
||||
Focused exact-head validation passed with local bind access: `pnpm exec vitest run --project @paperclipai/server server/src/__tests__/issue-agent-mutation-ownership-routes.test.ts` reported **142/142 passing** in 10.59 seconds (start 08:18:35; finish 08:18:45). Expected warning logs are produced by cases that inject revalidation failures. The corrected run was serialized and completed successfully. No timing savings are inferred from this test duration.
|
||||
|
||||
`git diff --check` passed for the changed test file; its exact source diff is zero added lines and 16 removed lines. No production mutation was performed in this change. A recommended preservation mutation is to temporarily remove the POST route's `createInput.createdByRunId = createdByRunId` assignment, require the retained PR case to fail its attribution assertion, then restore production byte-for-byte.
|
||||
|
||||
Whole-repository typecheck, test, build, and PR checks remain campaign-level gates.
|
||||
@@ -0,0 +1,31 @@
|
||||
# Issues service fixture replay audit — 2026-10-13
|
||||
|
||||
## Scope and savings
|
||||
|
||||
This candidate changes only `server/src/__tests__/issues-service.test.ts`. It consolidates repeated setup while retaining the observable list, count, description-preview, dependency-readiness, and deep-ancestor contracts. Production code, database fixture ownership, cleanup hooks, and `ensureIssueRelationsTable` are unchanged. The existing `seedIssueCompany`, `seedWorkspaceProject`, and `seedCodexCoder` helpers remain intact; the candidate uses existing company seed calls and preserves the Codex coder seed in the dependency keeper.
|
||||
|
||||
Against the existing stack, the test-file diff is 63 lines added and 218 removed: **155 net test lines removed**, including the reviewer-requested removal of an inline comment. The existing stack already shares seed helpers, so savings are smaller than the earlier candidate. Seven standalone test declarations are removed. All four description inputs and all three count calls remain. The 60-node ancestor chain remains; its descendants use one insert statement instead of 60. These are source and operation counts, not a measured CI speedup.
|
||||
|
||||
## Removal and keeper ledger
|
||||
|
||||
| Removed standalone case | Keeper and retained proof |
|
||||
| --- | --- |
|
||||
| `counts only unassigned issues for assigneeAgentId='null'` | `filters and counts unassigned issues with assigneeAgentId='null'` uses the assigned/unassigned fixture and explicitly asserts count `1` as well as the selected issue ID. |
|
||||
| `counts UUID-assigned issues with assigneeAgentId` | `filters and counts only issues assigned to the requested UUID` explicitly asserts count `1`. Its fixture includes the requested assignee, another assignee, and an added unassigned row, preserving the removed case's unassigned exclusion while exercising another-assignee exclusion. |
|
||||
| `rejects malformed assigneeAgentId filter values in count` | `rejects malformed assigneeAgentId filters in list and count` retains both independent calls and `/assigneeAgentId/i` rejection assertions. |
|
||||
| `marks list descriptions as not truncated when they fit the preview limit` | `trims large list payloads and preserves description preview boundaries` retains an exact 1,200-character input and asserts length `1200` and `descriptionTruncated: false`. |
|
||||
| `marks null list descriptions as not truncated` | The same preview keeper retains a null input and asserts null output and `descriptionTruncated: false`. |
|
||||
| `does not let description preview truncation split multibyte characters` | The same preview keeper retains 1,199 ASCII characters followed by an em dash and a suffix. It asserts length `1200`, the final em dash, and `descriptionTruncated: true`. The original 5,000-character input and null large-payload field assertions remain. Results are selected by ID rather than relying on row order. |
|
||||
| `treats blockers with no executionWorkspaceId as not subject to the workspace-finalize barrier` | `only returns dependents once every blocker is done` explicitly seeds both blocker workspace IDs as null. It retains the not-ready assertion with a remaining open blocker, then the exact dependent/assignee result after both finish, plus both blocker IDs and an explicit two-ID length check to retain the removed case’s exact-set proof. This success still fails if the workspace-finalize barrier starts requiring a workspace for unattached blockers. |
|
||||
|
||||
## Deep-chain setup
|
||||
|
||||
`finds the ancestor through an arbitrarily deep chain` retains all 60 descendants, each parent link, the selected leaf, and the expected ancestor ID. IDs and rows are assembled locally, then inserted together. Only redundant database round trips are removed; the traversal depth and cycle/closed-ancestor sibling cases are unchanged. The owner suite must confirm the batched self-referencing inserts against the real embedded PostgreSQL database.
|
||||
|
||||
## Validation
|
||||
|
||||
`git diff --check` passed. The adapted candidate passed the complete owner suite with embedded PostgreSQL enabled: **130/130 passing** in **29.51 seconds** (start 08:19:20), using `node_modules/.bin/vitest run --project @paperclipai/server server/src/__tests__/issues-service.test.ts`. This exact-head rerun validates the 60-row self-referencing batch insert after removing the inline comment. An initial sandboxed attempt could not open localhost sockets and was stopped; the completed run used permission to enable the PostgreSQL fixture. No baseline/candidate timing comparison was performed, so no runtime savings are claimed. Repository-wide checks and CI remain campaign-level gates.
|
||||
|
||||
## Deferred work
|
||||
|
||||
Database fixture pooling is deliberately deferred. Sharing the existing 11 database bootstraps across groups requires separate cleanup and ordering evidence, baseline/candidate timing, and a reversible experiment. This candidate changes none of that ownership.
|
||||
@@ -0,0 +1,36 @@
|
||||
# Onboarding route duplicate-test audit — 2026-10-13
|
||||
|
||||
## Scope and keeper map
|
||||
|
||||
This change removes two duplicate tests from `ui/src/lib/onboarding-route.test.ts`. The production owner is `ui/src/lib/onboarding-route.ts`. No production code changes.
|
||||
|
||||
| Removed test | Retained keeper and preserved proof |
|
||||
| --- | --- |
|
||||
| `takes no mission input, so no goal state can route around the agent step` | `resolveRouteOnboardingOptions — the agent step > opens an existing company on the agent step` uses the same path, prefix, and company array. Its exact result includes `ONBOARDING_AGENT_STEP`; the removed negative mission-step assertion follows from this full equality. |
|
||||
| `never opens on the mission step, whatever the company's goals say` | `onboardingStepForCompany > opens an existing company on the agent step` calls the same zero-argument function and asserts the exact returned step. The removed negative assertion was weaker. |
|
||||
|
||||
Neither removed test accepts a distinct input or protects an additional route branch. CompanyContext provider and resolver tests remain unchanged because they exercise a separate integration boundary.
|
||||
|
||||
## Savings
|
||||
|
||||
- Onboarding route declarations: **32 → 30**.
|
||||
- Onboarding route file: **364 → 331 lines**, a net reduction of **33 test lines**, including the unused mission-step import and blank separators.
|
||||
- The two focused files execute **52 → 50 cases**. No CI timing reduction is claimed.
|
||||
|
||||
## Validation
|
||||
|
||||
Baseline command, run from `ui/`:
|
||||
|
||||
```sh
|
||||
pnpm exec vitest run src/lib/onboarding-route.test.ts src/context/CompanyContext.test.tsx
|
||||
```
|
||||
|
||||
Baseline result: **2 files, 52 tests passed**, in 4.48 seconds.
|
||||
|
||||
Candidate command, run from `ui/`:
|
||||
|
||||
```sh
|
||||
node_modules/.bin/vitest run src/lib/onboarding-route.test.ts src/context/CompanyContext.test.tsx
|
||||
```
|
||||
|
||||
Candidate result: **2 files, 50 tests passed**, in 4.15 seconds. The modified onboarding route suite alone also passed **30/30**. `git diff --check` passed. No runtime savings are claimed.
|
||||
@@ -0,0 +1,52 @@
|
||||
# Pipeline bulk review test audit — 2026-10-13
|
||||
|
||||
## Scope and parent
|
||||
|
||||
This change owns only `server/src/__tests__/pipelines-routes.test.ts` and this receipt. Its exact parent is `e09990e009b1042c9fff212e24429a732853c324`, the current head of [PR #16175](https://github.com/paperclipai/paperclip/pull/16175), on `codex/test-audit-r19-adapter-utils-upload-case`. The dedicated branch is `codex/test-audit-pipeline-bulk-fixture`. No production file, lockfile, workflow, or held audit branch is changed. Do not merge this PR.
|
||||
|
||||
## Repeated fixture and retained proof
|
||||
|
||||
`bulk reviews partial successes without aborting stale items` previously created 50 independent cases and transitioned each to review. Rows 0–2 then received stale versions. Row 3 requested changes. Rows 4–49 all approved an otherwise identical case.
|
||||
|
||||
Keep rows 0–4. Change the fixture bound from 50 to 5 and the successful result count from 47 to 2. Preserve the HTTP 200 response, all three failures, every failure's `version_conflict` code, and the persisted request-changes stage `in_progress`. Add a persisted `done` stage assertion for row 4 after the bulk response. Thus both success paths still execute after multiple stale failures. The same actor, company, pipeline stages, versions, and complete request shape are retained.
|
||||
|
||||
This removes 90 setup HTTP mutations and 45 per-item review service calls. The new approval-detail read makes the net difference 134 operations. This is an operation count, not a measured time saving. The owner retains all 19 test cases. Test source changes by four inserted and two deleted lines; it gains two net lines.
|
||||
|
||||
## Historical intent and limits
|
||||
|
||||
Commit `43b005b704f80aea3ce37cab8136920749c73ee6` introduced the same fixture in [PR #7903](https://github.com/paperclipai/paperclip/pull/7903). Its title and assertions describe partial success. The introduction records no stress-test requirement or timing target. Both the original schema and current `server/src/routes/pipelines-schemas.ts:134` limit bulk review to 100 items. The 50-row fixture is not that limit.
|
||||
|
||||
The current route at `server/src/routes/pipelines.ts:827` processes each item independently and catches each item's error. `reviewCase` receives no batch-size input. Cases in this fixture have no parent, blocker, or linked execution relationships. Rows 5–49 differ only in unique case key/title/id and repeat row 4's approval input state.
|
||||
|
||||
A cross-check of all named pipeline tests in server, CLI, UI, shared, DB-schema, and tutorial E2E code found no independent 50-item bulk-review contract. The owner has explicit event-pagination and large-history tests at lines 727 and 776. Those tests remain unchanged. The original bulk fixture gave incidental medium-batch execution coverage; the smaller fixture preserves its asserted functional proof.
|
||||
|
||||
## Local validation and database blocker
|
||||
|
||||
Local database tests and production mutations were deliberately not started. The host still has 31 allocated SysV shared-memory IDs against `kern.sysv.shmmni = 32`. A prior isolated initdb failed with `could not create shared memory segment: No space left on device`. One remaining slot is not clear test headroom. No global IPC resource or other owner's process was changed.
|
||||
|
||||
Passed: `pnpm --config.manage-package-manager-versions=false --filter @paperclipai/server typecheck` (exit 0), including required Runner vendor and shared/plugin build dependencies. Passed: TypeScript AST/syntax validation, all 19 cases retained, all other 18 declarations AST-equivalent, and reversal of the two scalar edits plus the two added assertion lines exactly reconstructs the original test bytes. Passed: `git diff --check` and exact two-file scope review. Production source remains unchanged. The server typecheck excludes test files; the AST/syntax check separately covers this test edit.
|
||||
|
||||
Local owner, sibling, full tests, mutation proofs, and causal timing remain unverified. The authorized stacked PR delegates owner/sibling runtime validation to hosted CI. Repo-wide local tests and build were not run because the request permits non-DB verification and requires avoiding local database tests.
|
||||
|
||||
## Exact parent CI baseline
|
||||
|
||||
[PR CI run 38411804432](https://github.com/paperclipai/paperclip/actions/runs/38411804432) tested the exact parent SHA. Its [serialized shard 4/9](https://github.com/paperclipai/paperclip/actions/runs/38411804432/job/115345896667) passed the owner with 19 tests:
|
||||
|
||||
- Bulk-review case: 1,134 ms.
|
||||
- Owner tests and hooks: 4,239 ms.
|
||||
- Owner Vitest duration: 24.60 s.
|
||||
- Serial owner interval between suite-start markers: 25.519 s.
|
||||
- Shard test window from its start banner to final suite duration line: 309.323 s.
|
||||
- Full job interval from GitHub check timestamps: 375 s.
|
||||
|
||||
The [general server shard 12/12](https://github.com/paperclipai/paperclip/actions/runs/38411804432/job/115345897543) passed `pipelines-service.test.ts`, 32 tests, 4,272 ms for tests and hooks. Its grouped execution makes an isolated owner-duration comparison unavailable from that completion line alone.
|
||||
|
||||
The old serialized manifest weight is 20,408 ms, sampled on September 12. The general manifest sibling weight is 13,114 ms, averaged on October 10. These weights are historical balancing inputs, not a local baseline or a causal estimate of this change.
|
||||
|
||||
Capture candidate owner/shard logs from hosted CI and compare with this parent. Report tests/hooks, isolated owner duration, serial marker interval, and shard/job intervals separately. Unchanged sibling/neighbor costs can help expose runner variability. A single parent/candidate CI pair cannot establish causal speedup; transforms, imports, scheduling, runner load, and startup dominate owner wall time. The PR's Verification section and follow-up report will carry the candidate result once available.
|
||||
|
||||
## Deferred mutation proof
|
||||
|
||||
When local capacity permits, use the original and candidate bulk case with a clean owner/sibling run. Deliberately abort the bulk loop on the first stale item, and separately stop before the final retained approval. Require failures at the intended partial-success and approval assertions. Restore production byte-for-byte after each mutant. These mutation experiments are not claimed as completed by this PR.
|
||||
|
||||
Model: OpenAI `gpt-6.1-sol`; context window unavailable; repository analysis, shell tooling, TypeScript AST inspection, and non-DB verification.
|
||||
@@ -0,0 +1,213 @@
|
||||
# Proven provisioning test consolidation
|
||||
|
||||
Historical proof base: #16106 exact head 397459400c6e7b18b462dcac3d8886b390ca8e8c, extracted into an isolated temporary snapshot. All test and production owners match exact-head Git blobs. Disjoint shard candidate reverted before this sequence. All runs serial; no shared checkout edits, commits, pushes or PR actions.
|
||||
|
||||
Historical result: PROVEN with one preserved existing tool-availability skip. Owner scripts/__tests__/provision-worktree-self-heal.test.mjs shrinks 717 -> 707 lines (10 net); registered cases 35 -> 34; one repeated top-level bash runProvision launch retired. Nested subprocess savings unquantified. No CI-time claim.
|
||||
|
||||
Retire `falls back to an isolated config when the base CLI cannot boot`. Keeper `reconciles deployment mode from the registered source when reusing a guest config` is renamed `isolates fallback configuration and reconciles deployment mode from the registered source when reusing a guest config`.
|
||||
|
||||
Both originals allocate makeBaseWorkspace({helpExit:1, initExit:0}) and call runProvision(baseCwd) with identical defaults. Move all fallback stderr, persisted config source, real database-path containment, actual .env and pending seed-manifest assertions into keeper immediately after first successful launch and before changing source config. Only lexical result.stderr -> first.stderr changes. Retain original local_trusted, second real bash launch and config reuse/reconciliation receipts.
|
||||
|
||||
| Complete-owner phase | Cases | Pass | Fail | Skip | Exit |
|
||||
|---|---:|---:|---:|---:|---:|
|
||||
| baseline | 35 | 34 | 0 | 1 | 0 |
|
||||
| candidate | 34 | 33 | 0 | 1 | 0 |
|
||||
| database-path-escape-original | 35 | 32 | 2 | 1 | 1 |
|
||||
| database-path-escape-keeper | 34 | 32 | 1 | 1 | 1 |
|
||||
| restored-candidate | 34 | 33 | 0 | 1 | 0 |
|
||||
|
||||
Every accepted run has zero cancelled/todo. Existing skip: ok 20 - repairs an unhealthy base install under the lock and then uses the CLI # SKIP flock or git not available on this host
|
||||
|
||||
## Production regression and restoration
|
||||
|
||||
Change only generated fallback targetConfig.database.embeddedPostgresDataDir in scripts/provision-worktree.sh from path.resolve(instanceRoot, "db") to path.resolve(worktreeHome, "..", "misdirected-worktree-db"). This writes only a config value; it does not create or touch files at that escaped path. Original and keeper both fail the exact assertion `!path.relative(worktreesHome, dataDir).startsWith("..")`, reporting the actual persisted escaped path before keeper's second launch. No setup/timeout failure qualifies the control.
|
||||
|
||||
Original mutated complete owner has two direct failures: exact isolation assertion, plus separate reuse case's unchanged /Reusing existing isolated Paperclip worktree config/ guard when production correctly treats escaped-path config as stale. Candidate mutated complete owner has one failure: relocated exact isolation assertion. The exact mutation and relevant failures are included below. Production bytes restore in finally and hash-check before restored candidate (33 passing/1 unchanged skipped). Test owner restores to exact-head original after proof.
|
||||
|
||||
Initial default-sandbox baseline was rejected by real localhost binding EPERM: 35 cases, 32 passing, 2 setup failures, 1 existing skip. No candidate/mutation ran during that attempt. Those local reports are not bundled; these setup failures are not accepted controls. Approved escalation then ran the identical sequence with real localhost binding enabled, producing the accepted table above. No production behavior, assertions, deadlines, retries or skip logic changed.
|
||||
|
||||
## Exact executable hashes
|
||||
|
||||
- Original test: 29d758d74d32418ea4de53c6cea4409d29c5310252a10d558c19e08ba36a670a
|
||||
- Proven candidate test: ffacee5de45871dfe9bb2613aa05ffadb452e4c1f7188b8f0519d36d70d935b2
|
||||
- Restored production shell: 2d52e8e98eb913ca5fbfa3c508eb864a685ee11b7d503558cb0b2e2d517b3f48
|
||||
|
||||
Node subprocess.run waits/reaps every complete owner. Original test.after removes its allocated fixture roots. The historical cleanup record was `{"processSnapshotExit":0,"matchingOwnedFixtureProcesses":[],"allOwnedSourceRestored":true}`. No process from this proof remains when the snapshot check succeeds with an empty inventory. No production/path mutations remain.
|
||||
|
||||
## Inspectable reproduction
|
||||
|
||||
The results above are historical, recorded on 2026-10-13. This documentation repair
|
||||
checks the Git source and mutation hashes; it does not claim fresh test results.
|
||||
Historical raw reports remain local and are not bundled. The relevant failure
|
||||
excerpts and exact executed production edits are included here; no private proof
|
||||
file is needed to reconstruct the checks.
|
||||
|
||||
Run the block from a repository checkout with the public `base` and `head` Git
|
||||
revisions below. Fetch those public PR/revisions first if they are absent.
|
||||
Python 3.12+, Git and Node are required. No dependency installation is needed. Provisioning requires
|
||||
Bash and localhost binding permission; its existing tool-availability skip can
|
||||
vary with `flock`/Git availability. The recipe accepts either execution or that
|
||||
one named skip and adjusts only its passing/skip counts. All other case and
|
||||
intended failure counts must match. The table retains the historical host results.
|
||||
|
||||
The script uses an isolated snapshot and obtains the candidate test directly
|
||||
from its Git revision. It runs the full baseline and candidate owners, applies
|
||||
each mutation independently, checks the intended failing case, restores exact
|
||||
source bytes in `finally`, and reruns the full candidate. Counts are
|
||||
`[total, passed, failed, skipped-or-filtered]`. Original-owner mutation counts
|
||||
above are historical; this recipe repeats candidate sensitivity checks.
|
||||
Prefix the command with `AUDIT_RECONSTRUCT_ONLY=1` to verify source and mutation
|
||||
hashes without extracting a snapshot, installing dependencies or running tests.
|
||||
|
||||
```sh
|
||||
python3 - <<'PY'
|
||||
import hashlib, io, json, os, re, subprocess, tarfile, tempfile
|
||||
from pathlib import Path
|
||||
|
||||
spec = {'base': '397459400c6e7b18b462dcac3d8886b390ca8e8c',
|
||||
'head': '27865cb2c85921ef3c996c27bc2d662776a35d29',
|
||||
'owner': 'scripts/__tests__/provision-worktree-self-heal.test.mjs',
|
||||
'kind': 'tap',
|
||||
'hashes': {'scripts/__tests__/provision-worktree-self-heal.test.mjs': '29d758d74d32418ea4de53c6cea4409d29c5310252a10d558c19e08ba36a670a',
|
||||
'scripts/provision-worktree.sh': '2d52e8e98eb913ca5fbfa3c508eb864a685ee11b7d503558cb0b2e2d517b3f48'},
|
||||
'candidate_hash': 'ffacee5de45871dfe9bb2613aa05ffadb452e4c1f7188b8f0519d36d70d935b2',
|
||||
'baseline': [35, 34, 0, 1],
|
||||
'candidate': [34, 33, 0, 1],
|
||||
'mutations': [{'name': 'database-path-escape',
|
||||
'path': 'scripts/provision-worktree.sh',
|
||||
'changes': [[' embeddedPostgresDataDir: path.resolve(instanceRoot, "db"),\n',
|
||||
' embeddedPostgresDataDir: path.resolve(worktreeHome, "..", '
|
||||
'"misdirected-worktree-db"),\n']],
|
||||
'hash': '9fa060a915ec993b91d95ccf3c8f66a65f483713e8a82ffe194f667c4dc91066',
|
||||
'counts': [34, 32, 1, 1],
|
||||
'guard': 'isolates fallback configuration and reconciles deployment mode from the '
|
||||
'registered source when reusing a guest config',
|
||||
'message': 'to live under'}]}
|
||||
|
||||
def digest(data):
|
||||
return hashlib.sha256(data).hexdigest()
|
||||
|
||||
def blob(rev, path):
|
||||
return subprocess.check_output(["git", "show", rev + ":" + path])
|
||||
|
||||
owner = spec["owner"]
|
||||
original = {p: blob(spec["base"], p) for p in spec["hashes"]}
|
||||
candidate = blob(spec["head"], owner)
|
||||
assert all(digest(b) == spec["hashes"][p] for p, b in original.items())
|
||||
assert digest(candidate) == spec["candidate_hash"]
|
||||
mutants = []
|
||||
for m in spec["mutations"]:
|
||||
text = original[m["path"]].decode()
|
||||
for before, after in m["changes"]:
|
||||
assert text.count(before) == 1, (m["name"], "ambiguous mutation")
|
||||
text = text.replace(before, after)
|
||||
data = text.encode()
|
||||
assert digest(data) == m["hash"], m["name"]
|
||||
mutants.append((m, data))
|
||||
if os.environ.get("AUDIT_RECONSTRUCT_ONLY") == "1":
|
||||
print("Original, candidate and all mutation hashes match historical proof.")
|
||||
raise SystemExit(0)
|
||||
|
||||
archive = subprocess.check_output(["git", "archive", spec["base"]])
|
||||
with tempfile.TemporaryDirectory(prefix="paperclip-audit-") as directory:
|
||||
root = Path(directory)
|
||||
with tarfile.open(fileobj=io.BytesIO(archive)) as tar:
|
||||
tar.extractall(root, filter="data")
|
||||
if spec["kind"] != "tap":
|
||||
assert subprocess.check_output(["pnpm", "--version"], cwd=root, text=True).strip() == "9.15.4"
|
||||
subprocess.run(["pnpm", "install", "--frozen-lockfile"],
|
||||
cwd=root, check=True)
|
||||
|
||||
def run(label, expected, mutation=None):
|
||||
report = root / "audit-report.json"
|
||||
if report.exists():
|
||||
report.unlink()
|
||||
if spec["kind"] == "tap":
|
||||
command = ["node", "--test", "--test-reporter=tap", owner]
|
||||
elif spec["kind"] == "ui":
|
||||
command = ["pnpm", "--filter", "@paperclipai/ui",
|
||||
"exec", "vitest", "run", "src/pages/CompanyExport.test.tsx",
|
||||
"--maxWorkers=1", "--reporter=default", "--reporter=json",
|
||||
"--outputFile.json=" + str(report)]
|
||||
else:
|
||||
command = ["node", "node_modules/vitest/vitest.mjs", "run", "--config",
|
||||
"packages/adapters/codex-local/vitest.config.ts", owner,
|
||||
"--reporter=json", "--outputFile=" + str(report)]
|
||||
if mutation and mutation.get("selector"):
|
||||
command += ["-t", mutation["selector"]]
|
||||
result = subprocess.run(command, cwd=root, capture_output=True, text=True,
|
||||
timeout=180)
|
||||
output = result.stdout + result.stderr
|
||||
print(label, "exit", result.returncode, output)
|
||||
if spec["kind"] == "tap":
|
||||
counts = {k: int(v) for k, v in re.findall(
|
||||
r"^# (tests|pass|fail|skipped) (\d+)$", output, re.M)}
|
||||
actual = [counts[k] for k in ["tests", "pass", "fail", "skipped"]]
|
||||
assert actual[3] in (0, 1), (label, "unexpected skip count")
|
||||
if actual[3]:
|
||||
assert re.search(
|
||||
r"^ok \d+ - repairs an unhealthy base install under the lock and then uses the CLI # SKIP flock or git not available on this host$",
|
||||
output, re.M), (label, "unexpected skipped case")
|
||||
expected = expected.copy()
|
||||
expected[1] += expected[3] - actual[3]
|
||||
expected[3] = actual[3]
|
||||
if mutation:
|
||||
failures = re.findall(
|
||||
r"^not ok \d+ - (.*?)\n(.*?)(?=^(?:ok|not ok) \d+ - |^1\.\.|\Z)",
|
||||
output, re.M | re.S)
|
||||
assert any(name == mutation["guard"] and mutation["message"] in body
|
||||
and "ERR_ASSERTION" in body for name, body in failures), label
|
||||
else:
|
||||
data = json.loads(report.read_text())
|
||||
actual = [data[k] for k in ["numTotalTests", "numPassedTests",
|
||||
"numFailedTests", "numPendingTests"]]
|
||||
if mutation:
|
||||
hits = [a for suite in data["testResults"] for a in suite["assertionResults"]
|
||||
if a["status"] == "failed" and mutation["guard"] in a["fullName"]]
|
||||
assert any(mutation["message"] in msg for a in hits
|
||||
for msg in a["failureMessages"]), label
|
||||
if mutation.get("line"):
|
||||
assert any(f'CompanyExport.test.tsx:{mutation["line"]}:' in msg
|
||||
for a in hits for msg in a["failureMessages"]), label
|
||||
assert actual == expected, (label, actual, expected)
|
||||
assert result.returncode == (1 if mutation else 0), label
|
||||
|
||||
try:
|
||||
run("baseline", spec["baseline"])
|
||||
(root / owner).write_bytes(candidate)
|
||||
run("candidate", spec["candidate"])
|
||||
for m, data in mutants:
|
||||
try:
|
||||
(root / owner).write_bytes(candidate)
|
||||
(root / m["path"]).write_bytes(data)
|
||||
run(m["name"] + "-keeper", m["counts"], m)
|
||||
finally:
|
||||
for path, data in original.items():
|
||||
(root / path).write_bytes(data)
|
||||
assert all((root / p).read_bytes() == b for p, b in original.items())
|
||||
(root / owner).write_bytes(candidate)
|
||||
run("restored-candidate", spec["candidate"])
|
||||
finally:
|
||||
for path, data in original.items():
|
||||
(root / path).write_bytes(data)
|
||||
assert all((root / p).read_bytes() == b for p, b in original.items())
|
||||
PY
|
||||
```
|
||||
|
||||
Recorded intended failure excerpts (fixture path prefixes omitted):
|
||||
|
||||
```text
|
||||
database-path-escape-original
|
||||
falls back to an isolated config when the base CLI cannot boot
|
||||
'expected <fixture-root>/misdirected-worktree-db to live under <fixture-root>/paperclip-provision-home-GzsiQq'
|
||||
reconciles deployment mode from the registered source when reusing a guest config
|
||||
|-
|
||||
The input did not match the regular expression /Reusing existing isolated Paperclip worktree config/. Input:
|
||||
|
||||
'existing worktree config path is outside <fixture-root>/paperclip-provision-worktree-kroaza-bc89219c87b9: <fixture-root>/misdirected-worktree-db\n' +
|
||||
'Existing isolated Paperclip worktree config is stale for this host; regenerating.\n' +
|
||||
'No usable paperclipai CLI found; writing isolated fallback config without DB seeding.\n'
|
||||
database-path-escape-keeper
|
||||
isolates fallback configuration and reconciles deployment mode from the registered source when reusing a guest config
|
||||
'expected <fixture-root>/misdirected-worktree-db to live under <fixture-root>/paperclip-provision-home-Rv7iS2'
|
||||
```
|
||||
@@ -0,0 +1,50 @@
|
||||
# Shared access null DSN test consolidation
|
||||
|
||||
Date: 2026-10-13. Baseline commit: `9b4d0cd872ca1fc897f320cb181fc060f0bd5bf1`.
|
||||
|
||||
## Scope and keeper map
|
||||
|
||||
Only `packages/shared/src/validators/access.test.ts` changes for this consolidation. Retire `authSessionSchema > accepts a null sentryDsn` after moving its output assertion into `authSessionSchema > parses a session where user has a real name`.
|
||||
|
||||
Both cases used exactly the same input:
|
||||
|
||||
```ts
|
||||
{
|
||||
session: { id: "s1", userId: "u1" },
|
||||
user: { id: "u1", email: "a@b.com", name: "Jane", image: null },
|
||||
sentryDsn: null,
|
||||
}
|
||||
```
|
||||
|
||||
The keeper retains successful parsing and the exact real name, and now also asserts `result.success && result.data.sentryDsn` is `null`. Rejection or transformation of the null DSN remains detectable through the same schema call and input.
|
||||
|
||||
The missing-DSN rejection case and real-DSN acceptance/value case remain unchanged. Name/email normalization, malformed-email rejection and all four optional Sentry-environment rows remain unchanged. No production code changed; no runtime behavior changed.
|
||||
|
||||
## Exact reduction
|
||||
|
||||
- Retire **1 `it` declaration** and its **10-line block**, including the separating blank line.
|
||||
- Add **1 assertion line** to the existing keeper: **1 added / 10 removed**, or **9 net test lines removed**.
|
||||
- Access file: **185 lines before / 176 after**; **20 cases before / 19 after**. Its two `describe` declarations and its test-file isolation unit remain.
|
||||
- These are case and source-line reductions. No CI time saving was measured or claimed.
|
||||
|
||||
## Reproducible verification
|
||||
|
||||
Commands ran from `/private/tmp/paperclip-test-audit-pr-stack`, using the root Vitest project configuration and the package-shared project. Both commands ran complete files without a test-name filter.
|
||||
|
||||
Baseline:
|
||||
|
||||
```sh
|
||||
node_modules/.bin/vitest run --project @paperclipai/shared packages/shared/src/telemetry/client.test.ts packages/shared/src/telemetry/client-contract.test.ts packages/shared/src/validators/access.test.ts
|
||||
```
|
||||
|
||||
Result: **3 files passed, 53 cases passed**, zero failed/skipped/todo; Vitest duration **214 ms** (start 08:15:17). Access contributed 20 cases.
|
||||
|
||||
Candidate, after the access and telemetry consolidations:
|
||||
|
||||
```sh
|
||||
node_modules/.bin/vitest run --project @paperclipai/shared packages/shared/src/telemetry/client.test.ts packages/shared/src/validators/access.test.ts
|
||||
```
|
||||
|
||||
Result: **2 files passed, 44 cases passed**, zero failed/skipped/todo; Vitest duration **214 ms** (start 08:15:50). Access contributes 19 surviving cases, and telemetry contributes 25.
|
||||
|
||||
Both runs emitted the existing Vite native-config warning about `__dirname`; neither run failed. `git diff --check` passes. No production mutation experiment was run. Repo-wide typecheck, tests, build and CI were not run for this focused consolidation; this receipt does not claim PR readiness.
|
||||
@@ -0,0 +1,85 @@
|
||||
# ZIP codec owner consolidation
|
||||
|
||||
Date: 2026-10-13. Exact local proof parent: `c1ae082a7a49c239a22e5149e223a41325b0ba2d`.
|
||||
|
||||
## Integrated PR scope
|
||||
|
||||
PR #16118 now includes the already-reviewed child rollup from #16119, which was
|
||||
squash-merged into this branch. Its 47-file diff against #16116 also consolidates
|
||||
adapter upload, DB migration, telemetry/access, server route/interaction/issue,
|
||||
worktree and onboarding tests. It removes import-only native-runner aliases and
|
||||
updates their generator/design ownership references. No production behavior or
|
||||
exports change in this rollup. Each owner has its own dated receipt in
|
||||
`doc/plans/`; this ZIP receipt documents only the original incremental ZIP proof.
|
||||
Current-head CI and review cover the integrated PR; the focused historical counts
|
||||
below do not stand in for integrated validation. Newer master legacy/native
|
||||
adapter-selection regressions remain intact during the integration.
|
||||
|
||||
## Historical incremental ZIP scope
|
||||
|
||||
Proof parent is local CLI ZIP delivery commit `c1ae082a7a49c239a22e5149e223a41325b0ba2d`, the candidate for predecessor #16116. The original ZIP child changed only `packages/shared/src/portability-zip.test.ts` and this receipt. The parent already removed the CLI codec replay file and migrated nested blob classification, opaque ASCII blob and invalid archive bytes into shared keepers.
|
||||
|
||||
This child adds the exact Unicode path/text to that existing archive keeper, then retires two direct conversion cases. It contains no further CLI deletion and does not alter the predecessor PR. The final shared test bytes match the separately verified combined candidate based on #16075, but the controls below were rerun on this exact child parent.
|
||||
|
||||
## Candidate
|
||||
|
||||
Retire these shared direct-helper cases:
|
||||
|
||||
- `keeps blobs/ entries as base64 octet streams regardless of extension`.
|
||||
- `decodes valid UTF-8 entries to text and falls back to base64 for invalid bytes`.
|
||||
|
||||
Their primary keeper becomes the existing shared `round-trips STORE, DEFLATE, and base64 blob entries byte-exactly and strips the shared root` case. The archive keeper calls the real conversion function through the real reader. It now contains:
|
||||
|
||||
- Opaque blob bytes `[0x68, 0x69]`, which must become base64 `aGk=` despite being valid UTF8. This is stronger classification evidence than the removed invalid-byte fixture, which could produce base64 through the decoder fallback after classification broke.
|
||||
- The exact retired Unicode input, path and expected output: `tasks/pap-1/TASK.md` and `# Notes\n\ncafé ✅\n`.
|
||||
- Invalid non-blob bytes `[0x68, 0x69, 0xff, 0xfe, 0xc0]`, expected as base64 `aGn//sA=` at `notes/raw`.
|
||||
|
||||
The shared classifier also retains the CLI's unique nested-path negative, `blobs/nested/file`, in addition to its original positive and negative paths. Existing STORE, DEFLATE, root stripping and all ZIP security/default/limit cases remain. CLI filesystem filtering and transfer tests remain.
|
||||
|
||||
## Reproducible proof
|
||||
|
||||
Incremental test diff: 2 added, 23 removed, **21 net test lines removed**. Two registered shared conversion cases are retired. Shared cases go from 15 to 13. Production reduction is zero. `git diff --check` passes.
|
||||
|
||||
| Complete-file positive phase | Shared owner |
|
||||
| --- | --- |
|
||||
| Untouched parent baseline | 15/15 |
|
||||
| Incremental candidate | 13/13 |
|
||||
| Shared test file fully reverted | 15/15 |
|
||||
| Restored incremental candidate | 13/13 |
|
||||
| After production mutations restored | 13/13 |
|
||||
|
||||
All complete-file positive controls have zero failed, skipped/pending and todo tests. Runs were serial. No active Vitest or Playwright process remained when the supervisor released the test slot. No baseline failures were hidden or disabled.
|
||||
|
||||
From a dependency-ready checkout, run the complete owner command for each baseline/candidate/revert/restored phase:
|
||||
|
||||
```sh
|
||||
node node_modules/vitest/vitest.mjs run --no-file-parallelism --maxWorkers=1 \
|
||||
packages/shared/src/portability-zip.test.ts
|
||||
```
|
||||
|
||||
CLI transport was not rerun for this incremental child. This child does not touch transport files or production code. The separate combined proof on #16075 recorded 18/18 transport cases before, with and after the same final shared test bytes. Those results are related evidence, not exact-child test results.
|
||||
|
||||
## Production falsification and restoration
|
||||
|
||||
All four mutations change `packages/shared/src/portability-zip.ts` and are restored byte-for-byte separately. Focused negative controls each select one case, fail that case and skip 12 unrelated cases. Failures reach the selected keeper assertion. The same final test and production bytes also produced the detailed observation diffs in the separate combined proof.
|
||||
|
||||
1. Broaden `/(^|\/)blobs\/[^/]+$/` to `/(^|\/)blobs\/.+$/`. Run the shared owner with `-t 'matches blobs/'`. `blobs/nested/file` fails: expected false, received true.
|
||||
2. Change `if (isBlobStorePath(pathValue)) {` to `if (false) {`. Run with `-t 'round-trips STORE'`. Opaque blob output becomes plain `"hi"` instead of base64 `{ data: "aGk=", encoding: "base64", contentType: "application/octet-stream" }`.
|
||||
3. Change archive conversion `body: bytesToPortableFileEntry(archivePath, entryBytes),` to `body: isBlobStorePath(archivePath) ? bytesToPortableFileEntry(archivePath, entryBytes) : textDecoder.decode(entryBytes),`. Run with `-t 'round-trips STORE'`. `notes/raw` becomes lossy `"hi���"` instead of base64 `aGn//sA=`. Opaque-blob behavior remains intact, so this witnesses the invalid non-blob archive contract.
|
||||
4. Change `return Buffer.from(text, "utf8").equals(Buffer.from(bytes)) ? text : null;` to `return text.normalize("NFD");`. Run with `-t 'round-trips STORE'`. The Unicode text fails its exact comparison: composed `café` becomes decomposed `café`. This proves Unicode bytes remain protected after retiring the direct conversion cases.
|
||||
|
||||
Final restored production SHA256 matches the original. The final complete shared owner control passes 13/13. Repo-wide typecheck, tests, build, CI and reviewer checks remain pending; no PR-ready claim is made from this focused proof.
|
||||
|
||||
## Ownership, history and routing
|
||||
|
||||
Production consumers remain in CLI `resolveInlineSourceFromPath`, `resolveChunkedImportZip`, folder conversion/filtering and server `readImportZipArchive`. No tested production seam is dead. #10507 introduced CLI codec tests. #10531 moved the codec to shared and left CLI re-exports. #16075 removes earlier duplicate cases; the predecessor then removes the retained CLI replay file. This incremental child consolidates only the shared conversion cases.
|
||||
|
||||
CI runs shared in `general-workspaces-b` and CLI in `general-workspaces-a` through `scripts/run-vitest-stable.mjs` and `.github/workflows/pr-trusted.yml`. This child removes two shared executions. The predecessor already removed three CLI executions and one file. No measured CI time is available.
|
||||
|
||||
## SHA256 guards
|
||||
|
||||
- Parent shared test: `1664aca9760a18f33ce2657a4ac878a6015c8a6a43b4290dd88cd2b78663b6db`.
|
||||
- Candidate shared test: `64548931fa808612f3dad4889acb5265cd9344dba8414fc853bc7ed478fc6fc7`.
|
||||
- Parent and unchanged production owner: `b5860afd9ab301fb9cd44f3b3799c28d6fe6297fc891ebbe330b4b62bc53bd4e`.
|
||||
|
||||
- Test patch SHA256: `b0e9fcfbc198d19d679f7a6dd0613b7752ac9e37fcd383143af1631b00890f4f`.
|
||||
@@ -0,0 +1,9 @@
|
||||
VERIFIED: retire one repeated Tailscale idempotent-withdrawal execution while preserving its assertion union.
|
||||
|
||||
Exact parent: #16099 at 8e955181d8a3776acc86e4662de3c77933231a76. Production is unchanged. The test file changes from 593 to 559 lines and 22 to 21 cases (2 additions, 36 deletions); one reserve/expose/reserve/expose fake-broker sequence is removed. No wall-clock performance claim.
|
||||
|
||||
Full-owner controls, run serially: baseline 22/22 pass; candidate 21/21 pass; full revert 22/22 pass; restored candidate 21/21 pass. A real production mutation made the retained test fail at its removal-count assertion. Source was restored and byte-verified before the final passing run. Production SHA-256: c957d6ee89d61af6e8bfaac699bb4ed2d1d9fc1b12da89bffba613451cfd47d5.
|
||||
|
||||
Reproduce from the repository root with: pnpm --filter @paperclipai/tailscale-https-broker exec vitest run src/broker-core.test.ts
|
||||
|
||||
Mutation check: in packages/tailscale-https-broker/src/broker-core.ts, inside the leaseWasExposed branch that handles substituted ports, temporarily remove the statement that adds each substituted port to appliedPorts (currently: if (!appliedPorts.includes(port)) appliedPorts.push(port);). Re-run the same owner command: the retained test “withdraws an idempotently-skipped mapping whose listener was substituted” must fail at expect(fake.removeCalls).toBeGreaterThan(0). Restore the source and rerun to confirm the owner passes. This mutation skips the withdrawal admission and leaves the keeper's provider-removal assertion to catch it; it does not alter the candidate test.
|
||||
@@ -0,0 +1,54 @@
|
||||
# Telemetry client contract test consolidation
|
||||
|
||||
Date: 2026-10-13. Baseline commit: `9b4d0cd872ca1fc897f320cb181fc060f0bd5bf1`.
|
||||
|
||||
## Scope and keeper map
|
||||
|
||||
Retire only `packages/shared/src/telemetry/client-contract.test.ts` after moving its unique assertions into the complete owner suite, `packages/shared/src/telemetry/client.test.ts`.
|
||||
|
||||
| Retired contract case | Surviving owner keeper and protected regression |
|
||||
| --- | --- |
|
||||
| `emits only allow-set keys with schemaVersion '1' on every POST` | The count-split keeper now checks every envelope key against `CONTRACT_KEYS` (`app`, `schemaVersion`, `installId`, `version`, `events`, `batchId`) and every envelope's schema version against `"1"`. Extra wire fields and wrong schema versions remain detectable. |
|
||||
| `never exceeds the injected maxEventsPerBatch on any POST` | `splits more than maxEventsPerBatch events into multiple compliant POSTs` retains the injected count cap of 2 and exact `[2, 2, 1]` distribution for five queued events. Count violations and event loss remain detectable. |
|
||||
| `never exceeds the injected maxBodyBytes on any POST` | `splits a chunk whose serialized bytes exceed maxBodyBytes` retains the injected 900-byte cap and checks every raw POST body. It now also requires exactly six aggregate events, protecting against loss during byte splitting. |
|
||||
| `a large flush splits into N envelopes that are each count- and byte-compliant` | The count-split keeper now injects `maxBodyBytes = 4096` and checks every raw POST body against that same injected limit, alongside the count cap and exact five-event distribution. |
|
||||
| `retries a 429 and re-sends the identical batchId (server idempotency)` | `retries a 429 with the same batchId and eventually succeeds` now compares the retry's events with the original events, alongside equal batch IDs and exactly two attempts. Retry event remixing remains detectable. |
|
||||
| `does not retry a terminal 400 or 413` | The separate owner cases `does not retry a terminal 400` and `does not retry a terminal 413` remain unchanged. |
|
||||
| `derives a different batchId for the same events under a different installId` | The same-named owner case remains unchanged with the clock frozen across clients, isolating install identity from timestamp differences. |
|
||||
| `emits a batchId of at least 32 hex chars — 128-bit collision floor` | `emits a batchId of at least 32 hex chars (128-bit collision floor)` retains both the minimum length and lowercase hexadecimal format checks. |
|
||||
|
||||
The remaining owner controls for event registration, dynamic events, configuration, oversized/circular events, backoff, endpoint fallback and retry-store bounds are unchanged. No production code or generated telemetry contract changed; no runtime behavior changed. The generated contract was checked first and remains byte-identical because no event names, dimensions, or schema version changed. The telemetry README now records `client.test.ts` as the durable owner for transport contract assertions.
|
||||
|
||||
## Privacy review
|
||||
|
||||
Independent review of this change found no production telemetry client, event, config, type, generated-contract, retention, or payload construction changes. Event names, dimensions, schema version, identity and privacy transforms, destination, opt-out behavior, and retention remain unchanged. The tests use the existing localhost endpoint and stubbed fetch; the assertions preserve the wire allow-set, schema version, count/byte limits, and retry payload boundaries. Privacy impact: none in emitted behavior.
|
||||
|
||||
## Exact reduction
|
||||
|
||||
- Candidate file removed: **205 lines**, **8 `it` declarations**, **3 `describe` declarations**, and one Vitest test-file isolation unit.
|
||||
- Owner additions: 15 lines added and 1 replaced line removed, for 14 net owner lines added. No owner test declaration was added or removed.
|
||||
- Combined telemetry test diff: **15 added / 206 removed**, or **191 net test lines removed**.
|
||||
- Telemetry cases: **33 before / 25 after**. The separately consolidated access suite accounts for the other case removed from the combined focused run.
|
||||
- These are case, file and source-line reductions. No CI time saving was measured or claimed.
|
||||
|
||||
## Reproducible verification
|
||||
|
||||
Commands ran from `/private/tmp/paperclip-test-audit-pr-stack`, using the root Vitest project configuration and the package-shared project. Both commands ran complete files without a test-name filter.
|
||||
|
||||
Baseline:
|
||||
|
||||
```sh
|
||||
node_modules/.bin/vitest run --project @paperclipai/shared packages/shared/src/telemetry/client.test.ts packages/shared/src/telemetry/client-contract.test.ts packages/shared/src/validators/access.test.ts
|
||||
```
|
||||
|
||||
Result: **3 files passed, 53 cases passed**, zero failed/skipped/todo; Vitest duration **214 ms** (start 08:15:17).
|
||||
|
||||
Candidate, after both consolidations:
|
||||
|
||||
```sh
|
||||
node_modules/.bin/vitest run --project @paperclipai/shared packages/shared/src/telemetry/client.test.ts packages/shared/src/validators/access.test.ts
|
||||
```
|
||||
|
||||
Result: **2 files passed, 44 cases passed**, zero failed/skipped/todo; Vitest duration **214 ms** (start 08:15:50). The telemetry owner has 25 surviving cases; access has 19.
|
||||
|
||||
Both runs emitted the existing Vite native-config warning about `__dirname`; neither run failed. `git diff --check` passes. No production mutation experiment was run. Repo-wide typecheck, tests, build and CI were not run for this focused consolidation; this receipt does not claim PR readiness.
|
||||
@@ -0,0 +1,108 @@
|
||||
# Test audit: remove duplicate untracked-worktree execution
|
||||
|
||||
Date: 2026-10-13
|
||||
Discovery base: `418eb4623ae767b5c9ce28c1c3e9fcb98f63702e` (PR #16173).
|
||||
Stack replay base: `4a7d8ae4fc05acbdc5d2eefaf909fd3b29ab822c`.
|
||||
|
||||
This candidate removes one 21-line test and one redundant execution from
|
||||
`server/src/__tests__/workspace-runtime.test.ts`. It changes zero production
|
||||
lines. Complete owner/sibling proof passes 190 cases before and 189 after,
|
||||
with zero failures or skips in the accepted runs. The whole owner run was
|
||||
**36.124 seconds slower** after the change. No whole-file CI speedup is claimed.
|
||||
|
||||
## Retired case and keeper
|
||||
|
||||
Retire `does not reset a reused worktree with untracked changes` (baseline
|
||||
line 1172). Keep `does not reset a reused worktree with untracked changes when
|
||||
status.showUntrackedFiles=no` unchanged (candidate line 1172).
|
||||
|
||||
The keeper repeats all ten original statements, in the same order, and adds
|
||||
one real Git configuration call. An AST comparison preserves identifiers,
|
||||
string bytes, expressions, and assertion order; it ignores source offsets and
|
||||
comments. Both cases create a real repository, bare remote, clone and managed
|
||||
worktree, write the same scratch bytes, advance the remote, and realize reuse.
|
||||
All four receipts remain: reused rather than created, unchanged HEAD, exact
|
||||
scratch bytes, and the one-commit base-drift warning. The keeper also verifies
|
||||
that the guard works when Git configuration hides untracked files.
|
||||
|
||||
`refreshUnstartedWorktreeToBase` always requests `--untracked-files=all` and
|
||||
branches on returned dirtiness, not the configuration value. Thus the added
|
||||
configuration does not select a separate production decision. Its caller is
|
||||
`realizeExecutionWorkspace`, reached by heartbeat workspace preparation.
|
||||
Both cases were introduced together in PR #8412. No test-only seam becomes
|
||||
unused. The clean fast-forward, task-commit protection, exact-branch no-reset,
|
||||
authentication and runtime lifecycle cases remain separate and unchanged.
|
||||
An independent preservation review approved this exact deletion before edits.
|
||||
|
||||
## Regression control
|
||||
|
||||
The unmodified keeper passes. Changing only the owner's dirty condition from
|
||||
`status.trim().length > 0` to the impossible `< 0` makes the same keeper fail
|
||||
at its direct unchanged-HEAD assertion. The failed check reads the actual Git
|
||||
HEAD; it is not a timeout or setup failure. Production bytes were restored
|
||||
exactly, with SHA-256 `e45729293762be132b74f8eb0efe1e4b8fbefaf96839c28dcc1ef255fe97d56c`.
|
||||
The replay parent's owner and original test hashes match the measured base.
|
||||
|
||||
## Observed cost and limitations
|
||||
|
||||
The accepted complete baseline passes 175 owner plus 15 scheduler cases.
|
||||
The accepted complete candidate passes 174 owner plus the same 15 scheduler
|
||||
cases. Owner windows are 157.794 seconds before and 193.918 seconds after.
|
||||
This pair does not establish a whole-suite runtime reduction.
|
||||
|
||||
Six completed runs select only the two untracked cases before deletion and the
|
||||
one keeper after deletion. The order is baseline/candidate/candidate/baseline/
|
||||
baseline/candidate. All selected cases pass. Median selected execution drops
|
||||
from 2.007489 seconds to 0.755868 seconds: an observed 1.251621-second reduction.
|
||||
The retired case alone takes 0.958–1.129 seconds, median 1.081 seconds, in those
|
||||
baseline samples (0.633 seconds in the accepted complete baseline).
|
||||
Process wall time includes large variable import costs; its median drops from
|
||||
19.028 to 14.482 seconds, but that difference is not attributed to this deletion.
|
||||
|
||||
| Sample | Variant | Selected execution seconds | Process wall seconds |
|
||||
| --- | --- | ---: | ---: |
|
||||
| 1 | baseline | 2.007 | 19.028 |
|
||||
| 2 | candidate | 1.249 | 14.482 |
|
||||
| 3 | candidate | 0.742 | 9.412 |
|
||||
| 4 | baseline | 2.291 | 14.911 |
|
||||
| 5 | baseline | 1.726 | 19.374 |
|
||||
| 6 | candidate | 0.756 | 15.809 |
|
||||
|
||||
The first sandbox baseline was invalid because socket/process fixtures lacked
|
||||
host permissions. An initial permitted candidate attempt passed 179 assertions,
|
||||
failed before ten startup-reconciliation cases could run, and exposed no failed
|
||||
test assertion. Its JSON did not preserve the hook error. The unchanged group
|
||||
then passed all ten cases with full reporters, and the final complete candidate
|
||||
passed all 189. Other concurrent work reported exhausted Postgres shared-memory
|
||||
identifiers. That is consistent with setup contention, not proof of the precise
|
||||
cause of this initial failure. Neither invalid run supplies accepted proof or
|
||||
speedup evidence. No timeouts, retries, skips, fixtures or production code changed.
|
||||
|
||||
## Reproduction and provenance
|
||||
|
||||
Run from `server/` with the repository Vitest executable:
|
||||
|
||||
```sh
|
||||
pnpm exec vitest run src/__tests__/workspace-runtime.test.ts src/services/workspace-git-operation-scheduler.test.ts
|
||||
pnpm exec vitest run src/__tests__/workspace-runtime.test.ts -t 'does not reset a reused worktree with untracked changes'
|
||||
```
|
||||
|
||||
The isolated checkout uses external dependency links and candidate-local
|
||||
workspace links; the shared checkout's sources were not edited. Node 26.4.0
|
||||
and Vitest 5.0.3 produced the local evidence. Broad workspace typecheck, build
|
||||
and default full tests were not repeated locally for this 21-line deletion;
|
||||
PR checks provide those gates. The targeted server no-emit typecheck and
|
||||
`git diff --check` pass. Browser suites did not change.
|
||||
|
||||
Raw reports stay in the temporary audit directory. Their SHA-256 digests are:
|
||||
|
||||
| Receipt | SHA-256 |
|
||||
| --- | --- |
|
||||
| Accepted complete baseline | `c232815e2cda75bea004a9025cd5f8e3dbaeb110cba9821e72df20bc164337cb` |
|
||||
| Accepted complete candidate | `182c030d0385e36d7f16f4ad2821124391daf16597cc7e6098f468a5d2f927d8` |
|
||||
| Keeper regression control | `e182bb2e8297dc1630dfb379eaf7a8fc32714f7e5269d5e9fd17a596c0b03cff` |
|
||||
| Six timing samples | `09ac6c640a67d8db20928c338f93f865fa5180b1c7fb7691a43a6c364caee3ac` |
|
||||
| Original owner test | `89a5ad0dd1400880695942e049a91b18a92e0469dc6a8c2cafc5f27e5747688a` |
|
||||
| Candidate owner test | `d7f09f62d92a853de3ed61a14fe941fcdc934d41d3672da0c72a3143cdef6ad2` |
|
||||
|
||||
This follows the [test-audit workflow](https://github.com/openclaw/openclaw/blob/main/.agents/skills/test-audit/SKILL.md).
|
||||
@@ -0,0 +1,260 @@
|
||||
# Proven shard test consolidation
|
||||
|
||||
Historical proof base: #16099 exact tree 8e955181d8a3776acc86e4662de3c77933231a76, extracted with git archive into an isolated temporary snapshot. Node built-in tests require no dependency installation. All runs serial; no shared checkout edits, commits, pushes or PRs.
|
||||
|
||||
Historical result: PROVEN. Retire three repeated executions, preserving all original assertions in named keepers. Test lines 547 -> 521 (26 net removed, including redundant blank normalization); registered cases 32 -> 29; exactly 22 repeated dry-run Node calls removed: 9 serialized partition launches, 12 PR partition launches, 1 general shard-zero launch. The subprocess delta comes from exact unchanged loop bounds/args, not a sampled timing estimate. No CI-time improvement claimed.
|
||||
|
||||
| Complete-owner phase | Tests | Pass | Fail | Exit |
|
||||
|---|---:|---:|---:|---:|
|
||||
| baseline | 32 | 32 | 0 | 0 |
|
||||
| candidate | 29 | 29 | 0 | 0 |
|
||||
| serialized-duplicate-original | 32 | 31 | 1 | 1 |
|
||||
| serialized-duplicate-keeper | 29 | 28 | 1 | 1 |
|
||||
| balance-wrong-bin-original | 32 | 28 | 4 | 1 |
|
||||
| balance-wrong-bin-keeper | 29 | 25 | 4 | 1 |
|
||||
| route-wrong-lane-original | 32 | 30 | 2 | 1 |
|
||||
| route-wrong-lane-keeper | 29 | 28 | 1 | 1 |
|
||||
| restored-candidate | 29 | 29 | 0 | 0 |
|
||||
| stack-candidate | 29 | 29 | 0 | 0 |
|
||||
|
||||
Every run has 0 skipped/cancelled/todo. The 13 failures in mutation runs are deliberate direct assertion failures; no setup, worker or timeout failures. Unmutated baseline/candidate/restored/integrated controls all pass.
|
||||
|
||||
## Exact keeper and regression guards
|
||||
|
||||
- Serialized completeness moves into serialized duration-balance keeper. Mutate selectSerializedSuites to duplicate one actual selected file on shard zero. Original and keeper fail `every serialized suite must be selected exactly once`: 159 actual vs 158 expected. Each full owner has exactly one failing case.
|
||||
- PR duration-balance moves into PR exact-coverage keeper. Invert scheduler's lightest-bin `<` comparison to `>`. Original and keeper directly fail `shard weight spread 5003719.5ms exceeds heaviest suite 136113ms`. Each full owner has four failing cases: synthetic skew balance, empty-manifest uniform balance, real serialized balance, real general balance. All are direct meaningful scheduling assertions; complete coverage alone would miss the regression.
|
||||
- Route/authz exclusion moves into general partition keeper's existing per-file loop, extending the unchanged guard from shard zero to all shards. Actual executed mutation adds a real serialized route to the dry-run general shard-zero selection: `server/src/__tests__/access-routes-hidden-floor.test.ts`. Original route guard and keeper fail the identical route-exclusion assertion naming that actual path. Original owner has two failures (also total count); keeper has one, reaching the relocated route guard before the count assertion. The executable mutation differs from the discovery-map suggestion only in using the selected dry-run membership expression directly; it protects the same wrong-lane behavior.
|
||||
|
||||
Production modifications were applied one at a time; each pair ran complete original and candidate test owners under the same mutated bytes. Original test restored between groups. Every production owner restored in finally and hash-verified. Final restored-candidate run passes 29/29, and isolated baseline snapshot subsequently restores all three owners to exact base bytes.
|
||||
|
||||
## Hashes and stacked integration
|
||||
|
||||
- Original test SHA256: 3b658c7ff55e35619d70ec8381325d07777c3a46a851edc7f5c5d84a7976eacc
|
||||
- Proven candidate test SHA256: 58ecff8ddceecb8e0c44240fa3dbf7ae6a9756dbac35b5ad52a14e655cfc8327
|
||||
- Restored run-vitest-stable.mjs SHA256: 71da62d4317591b590f877436ac16c6185b650b497b7fa843b68c801ecb4f353
|
||||
- Restored general-server-shard.mjs SHA256: ce809911cac307063fc2746118c1d6229c280e3d866b82ee5b776c89f5c016f3
|
||||
|
||||
Fetched public branch into an isolated bare Git directory after the default sandbox attempt failed DNS resolution. Fetch succeeds through approved network escalation and resolves exactly #16106 head 397459400c6e7b18b462dcac3d8886b390ca8e8c. All seven relevant test/production owner blobs were identical to the #16099 proof base. The exact proven patch passes git apply --check, applies without conflict to an extracted #16106 snapshot, retains the candidate hash, and passes the complete owner 29/29 on that snapshot. No cherry-pick or rebase commit was created.
|
||||
|
||||
## Inspectable reproduction
|
||||
|
||||
The results above are historical, recorded on 2026-10-13. This documentation repair
|
||||
checks the Git source and mutation hashes; it does not claim fresh test results.
|
||||
Historical raw reports remain local and are not bundled. The relevant failure
|
||||
excerpts and exact executed production edits are included here; no private proof
|
||||
file is needed to reconstruct the checks.
|
||||
|
||||
Run the block from a repository checkout with the public `base` and `head` Git
|
||||
revisions below. Fetch those public PR/revisions first if they are absent.
|
||||
Python 3.12+, Git and Node are required. No dependency installation is needed.
|
||||
|
||||
The script uses an isolated snapshot and obtains the candidate test directly
|
||||
from its Git revision. It runs the full baseline and candidate owners, applies
|
||||
each mutation independently, checks the intended failing case, restores exact
|
||||
source bytes in `finally`, and reruns the full candidate. Counts are
|
||||
`[total, passed, failed, skipped-or-filtered]`. Original-owner mutation counts
|
||||
above are historical; this recipe repeats candidate sensitivity checks.
|
||||
Prefix the command with `AUDIT_RECONSTRUCT_ONLY=1` to verify source and mutation
|
||||
hashes without extracting a snapshot, installing dependencies or running tests.
|
||||
|
||||
```sh
|
||||
python3 - <<'PY'
|
||||
import hashlib, io, json, os, re, subprocess, tarfile, tempfile
|
||||
from pathlib import Path
|
||||
|
||||
spec = {'base': '8e955181d8a3776acc86e4662de3c77933231a76',
|
||||
'head': 'f750c5af0581ea844997d9ea4ee55053a29c775d',
|
||||
'owner': 'scripts/__tests__/run-vitest-stable-shard.test.mjs',
|
||||
'kind': 'tap',
|
||||
'hashes': {'scripts/__tests__/run-vitest-stable-shard.test.mjs': '3b658c7ff55e35619d70ec8381325d07777c3a46a851edc7f5c5d84a7976eacc',
|
||||
'scripts/run-vitest-stable.mjs': '71da62d4317591b590f877436ac16c6185b650b497b7fa843b68c801ecb4f353',
|
||||
'scripts/general-server-shard.mjs': 'ce809911cac307063fc2746118c1d6229c280e3d866b82ee5b776c89f5c016f3'},
|
||||
'candidate_hash': '58ecff8ddceecb8e0c44240fa3dbf7ae6a9756dbac35b5ad52a14e655cfc8327',
|
||||
'baseline': [32, 32, 0, 0],
|
||||
'candidate': [29, 29, 0, 0],
|
||||
'mutations': [{'name': 'balance-wrong-bin',
|
||||
'path': 'scripts/general-server-shard.mjs',
|
||||
'changes': [[' if (shards[index].totalWeight < shards[target].totalWeight) {\n',
|
||||
' if (shards[index].totalWeight > shards[target].totalWeight) {\n']],
|
||||
'hash': 'a654c5cbfed571ffff107623bc1dec25a5aa3982084d608f6cade19a0d84d75d',
|
||||
'counts': [29, 25, 4, 0],
|
||||
'guard': '12 PR without-chat shards plus the dedicated chat and native-runner lanes '
|
||||
'cover the original server group exactly',
|
||||
'message': 'shard weight spread 5003719.5ms exceeds heaviest suite 136113ms'},
|
||||
{'name': 'route-wrong-lane',
|
||||
'path': 'scripts/run-vitest-stable.mjs',
|
||||
'changes': [[' ? selectGeneralServerShard(\n',
|
||||
' ? [...(options.shardIndex === 0 ? '
|
||||
'[routeTests.find((routeTest) => '
|
||||
'routeTestPattern.test(routeTest.repoPath)).repoPath] : []), '
|
||||
'...selectGeneralServerShard(\n'],
|
||||
[' )\n', ' )]\n']],
|
||||
'hash': '230d86c678511ae08bdeaea1c86b6b79c433ffedacffc28eb4ede7d4821a743f',
|
||||
'counts': [29, 28, 1, 0],
|
||||
'guard': 'the general-server shards form a complete, non-overlapping partition',
|
||||
'message': 'route/authz suite must stay in the serialized lane, not general-server: '
|
||||
'server/src/__tests__/access-routes-hidden-floor.test.ts'},
|
||||
{'name': 'serialized-duplicate',
|
||||
'path': 'scripts/run-vitest-stable.mjs',
|
||||
'changes': [[' return shardFiles.map((file) => byRepoPath.get(file));\n',
|
||||
' return [...shardFiles, ...(shardIndex === 0 ? shardFiles.slice(0, 1) : '
|
||||
'[])].map((file) => byRepoPath.get(file));\n']],
|
||||
'hash': '13c8a46d0037c0594510404c6e6e81c1bf8559d157754082982a2796fbe0d604',
|
||||
'counts': [29, 28, 1, 0],
|
||||
'guard': 'the real serialized shard partition is complete, non-overlapping and '
|
||||
'duration-balanced',
|
||||
'message': 'every serialized suite must be selected exactly once'}]}
|
||||
|
||||
def digest(data):
|
||||
return hashlib.sha256(data).hexdigest()
|
||||
|
||||
def blob(rev, path):
|
||||
return subprocess.check_output(["git", "show", rev + ":" + path])
|
||||
|
||||
owner = spec["owner"]
|
||||
original = {p: blob(spec["base"], p) for p in spec["hashes"]}
|
||||
candidate = blob(spec["head"], owner)
|
||||
assert all(digest(b) == spec["hashes"][p] for p, b in original.items())
|
||||
assert digest(candidate) == spec["candidate_hash"]
|
||||
mutants = []
|
||||
for m in spec["mutations"]:
|
||||
text = original[m["path"]].decode()
|
||||
for before, after in m["changes"]:
|
||||
assert text.count(before) == 1, (m["name"], "ambiguous mutation")
|
||||
text = text.replace(before, after)
|
||||
data = text.encode()
|
||||
assert digest(data) == m["hash"], m["name"]
|
||||
mutants.append((m, data))
|
||||
if os.environ.get("AUDIT_RECONSTRUCT_ONLY") == "1":
|
||||
print("Original, candidate and all mutation hashes match historical proof.")
|
||||
raise SystemExit(0)
|
||||
|
||||
archive = subprocess.check_output(["git", "archive", spec["base"]])
|
||||
with tempfile.TemporaryDirectory(prefix="paperclip-audit-") as directory:
|
||||
root = Path(directory)
|
||||
with tarfile.open(fileobj=io.BytesIO(archive)) as tar:
|
||||
tar.extractall(root, filter="data")
|
||||
if spec["kind"] != "tap":
|
||||
assert subprocess.check_output(["pnpm", "--version"], cwd=root, text=True).strip() == "9.15.4"
|
||||
subprocess.run(["pnpm", "install", "--frozen-lockfile"],
|
||||
cwd=root, check=True)
|
||||
|
||||
def run(label, expected, mutation=None):
|
||||
report = root / "audit-report.json"
|
||||
if report.exists():
|
||||
report.unlink()
|
||||
if spec["kind"] == "tap":
|
||||
command = ["node", "--test", "--test-reporter=tap", owner]
|
||||
elif spec["kind"] == "ui":
|
||||
command = ["pnpm", "--filter", "@paperclipai/ui",
|
||||
"exec", "vitest", "run", "src/pages/CompanyExport.test.tsx",
|
||||
"--maxWorkers=1", "--reporter=default", "--reporter=json",
|
||||
"--outputFile.json=" + str(report)]
|
||||
else:
|
||||
command = ["node", "node_modules/vitest/vitest.mjs", "run", "--config",
|
||||
"packages/adapters/codex-local/vitest.config.ts", owner,
|
||||
"--reporter=json", "--outputFile=" + str(report)]
|
||||
if mutation and mutation.get("selector"):
|
||||
command += ["-t", mutation["selector"]]
|
||||
result = subprocess.run(command, cwd=root, capture_output=True, text=True,
|
||||
timeout=180)
|
||||
output = result.stdout + result.stderr
|
||||
print(label, "exit", result.returncode, output)
|
||||
if spec["kind"] == "tap":
|
||||
counts = {k: int(v) for k, v in re.findall(
|
||||
r"^# (tests|pass|fail|skipped) (\d+)$", output, re.M)}
|
||||
actual = [counts[k] for k in ["tests", "pass", "fail", "skipped"]]
|
||||
if mutation:
|
||||
failures = re.findall(
|
||||
r"^not ok \d+ - (.*?)\n(.*?)(?=^(?:ok|not ok) \d+ - |^1\.\.|\Z)",
|
||||
output, re.M | re.S)
|
||||
assert any(name == mutation["guard"] and mutation["message"] in body
|
||||
and "ERR_ASSERTION" in body for name, body in failures), label
|
||||
else:
|
||||
data = json.loads(report.read_text())
|
||||
actual = [data[k] for k in ["numTotalTests", "numPassedTests",
|
||||
"numFailedTests", "numPendingTests"]]
|
||||
if mutation:
|
||||
hits = [a for suite in data["testResults"] for a in suite["assertionResults"]
|
||||
if a["status"] == "failed" and mutation["guard"] in a["fullName"]]
|
||||
assert any(mutation["message"] in msg for a in hits
|
||||
for msg in a["failureMessages"]), label
|
||||
if mutation.get("line"):
|
||||
assert any(f'CompanyExport.test.tsx:{mutation["line"]}:' in msg
|
||||
for a in hits for msg in a["failureMessages"]), label
|
||||
assert actual == expected, (label, actual, expected)
|
||||
assert result.returncode == (1 if mutation else 0), label
|
||||
|
||||
try:
|
||||
run("baseline", spec["baseline"])
|
||||
(root / owner).write_bytes(candidate)
|
||||
run("candidate", spec["candidate"])
|
||||
for m, data in mutants:
|
||||
try:
|
||||
(root / owner).write_bytes(candidate)
|
||||
(root / m["path"]).write_bytes(data)
|
||||
run(m["name"] + "-keeper", m["counts"], m)
|
||||
finally:
|
||||
for path, data in original.items():
|
||||
(root / path).write_bytes(data)
|
||||
assert all((root / p).read_bytes() == b for p, b in original.items())
|
||||
(root / owner).write_bytes(candidate)
|
||||
run("restored-candidate", spec["candidate"])
|
||||
finally:
|
||||
for path, data in original.items():
|
||||
(root / path).write_bytes(data)
|
||||
assert all((root / p).read_bytes() == b for p, b in original.items())
|
||||
PY
|
||||
```
|
||||
|
||||
Recorded intended failure excerpts (fixture path prefixes omitted):
|
||||
|
||||
```text
|
||||
balance-wrong-bin-original
|
||||
duration-aware partition balances skewed weights better than round-robin
|
||||
'expected near-even shard weights, got 90600, 0, 0'
|
||||
a missing or malformed manifest degrades to uniform weights
|
||||
|-
|
||||
Expected values to be strictly equal:
|
||||
|
||||
4 !== 0
|
||||
the real serialized shard partition is duration-balanced
|
||||
'serialized shard weight spread 2061439ms exceeds heaviest suite 165058ms: 2061439, 0, 0, 0, 0, 0, 0, 0, 0'
|
||||
the real shard partition is duration-balanced
|
||||
'shard weight spread 5003719.5ms exceeds heaviest suite 136113ms: 5003719.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0'
|
||||
balance-wrong-bin-keeper
|
||||
duration-aware partition balances skewed weights better than round-robin
|
||||
'expected near-even shard weights, got 90600, 0, 0'
|
||||
a missing or malformed manifest degrades to uniform weights
|
||||
|-
|
||||
Expected values to be strictly equal:
|
||||
|
||||
4 !== 0
|
||||
the real serialized shard partition is complete, non-overlapping and duration-balanced
|
||||
'serialized shard weight spread 2061439ms exceeds heaviest suite 165058ms: 2061439, 0, 0, 0, 0, 0, 0, 0, 0'
|
||||
12 PR without-chat shards plus the dedicated chat and native-runner lanes cover the original server group exactly
|
||||
'shard weight spread 5003719.5ms exceeds heaviest suite 136113ms: 5003719.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0'
|
||||
route-wrong-lane-original
|
||||
the general-server shards form a complete, non-overlapping partition
|
||||
|-
|
||||
every suite must be selected exactly once
|
||||
|
||||
890 !== 889
|
||||
a route/authz suite never leaks into the general-server shards
|
||||
'route/authz suite must stay in the serialized lane, not general-server: server/src/__tests__/access-routes-hidden-floor.test.ts'
|
||||
route-wrong-lane-keeper
|
||||
the general-server shards form a complete, non-overlapping partition
|
||||
'route/authz suite must stay in the serialized lane, not general-server: server/src/__tests__/access-routes-hidden-floor.test.ts'
|
||||
serialized-duplicate-original
|
||||
the serialized shards form a complete, non-overlapping partition
|
||||
|-
|
||||
every serialized suite must be selected exactly once
|
||||
|
||||
159 !== 158
|
||||
serialized-duplicate-keeper
|
||||
the real serialized shard partition is complete, non-overlapping and duration-balanced
|
||||
|-
|
||||
every serialized suite must be selected exactly once
|
||||
|
||||
159 !== 158
|
||||
```
|
||||
@@ -0,0 +1,64 @@
|
||||
# Delivery fixture consolidation receipt
|
||||
|
||||
Exact parent: #16111, `06c1b2035df44fa03c065ddd69e8bf8df8513b86`.
|
||||
|
||||
The first delivery test in `server/src/__tests__/execution-workspaces-service.test.ts` creates a second Git topology that `seedTerminalWorkspace()` already creates. `candidate.patch` removes the manual repository/worktree and redundant PR-head overwrite. The original DB update and its updatedAt timing remain, with two path references redirected to the seeded fixture.
|
||||
|
||||
Savings: +2/-17, net 15 test lines; one repository/worktree and 11 duplicate fixture Git subprocesses. All 67 registered cases remain. All six keeper assertions and 61 other declaration ASTs are unchanged. The 12 retained keeper statements match after the physical-path alias.
|
||||
|
||||
| Phase | Passed | Failed | Skipped |
|
||||
|---|---:|---:|---:|
|
||||
| Baseline | 67 | 0 | 0 |
|
||||
| Candidate | 67 | 0 | 0 |
|
||||
| Full revert | 67 | 0 | 0 |
|
||||
| Production mutation | 50 | 17 | 0 |
|
||||
| Restored candidate | 67 | 0 | 0 |
|
||||
|
||||
The production mutation in `server/src/services/execution-workspaces.ts` incorrectly requires Git ancestry for merged-PR delivery. The exact intended keeper fails at candidate test line 542: `unmerged` received instead of `merged_via_pr`. Full mutation failure evidence is in `proof/mutation-pr-ancestry.json`.
|
||||
|
||||
Source files are restored byte-for-byte, HEAD is unchanged, and the scratch checkout is clean. No branch or PR was created by the proof agent. No shared-checkout source was edited. No further owner tests are running. Runtime slot reservation arrived after this replay started; it finished during stop attempts and may have overlapped the other non-DB lane. No global serialization or CI timing saving is claimed.
|
||||
|
||||
`receipt.json` uses checkout-relative source paths and evidence-relative artifacts. Commands run from `server/`; set `AUDIT_EVIDENCE_DIR` to this folder. Baseline source snapshots, all five reports/logs, mutation patch and AST proof are included in `proof/`. The reviewed candidate is only `candidate.patch`; no mutation belongs in the proposed change.
|
||||
|
||||
## Reproduce the integrated candidate
|
||||
|
||||
The 67-case counts, mutation result and patch hash above are historical results
|
||||
from the original proof parent. They are not fresh results on current master.
|
||||
The integrated replay below uses immutable public revisions from this PR's
|
||||
rebuilt parent and candidate. Its test-only patch is still +2/-17; newer unrelated
|
||||
owner tests stay in both baseline and candidate. Do not compare current HEAD to
|
||||
the older historical proof parent.
|
||||
|
||||
Run from a dependency-ready repository checkout (Git, Node and the repository's
|
||||
installed dependencies are required):
|
||||
|
||||
```sh
|
||||
base=1108f714ef42b0c59fea6916647e132e414c7cab
|
||||
candidate=fa7bc838926164781a1f1170c382819ba86e5a9d
|
||||
git fetch https://github.com/paperclipai/paperclip.git "$base" "$candidate"
|
||||
replay_dir=$(mktemp -d)
|
||||
git diff "$base" "$candidate" -- server/src/__tests__/execution-workspaces-service.test.ts > "$replay_dir/candidate.patch"
|
||||
git diff --numstat "$base" "$candidate" -- server/src/__tests__/execution-workspaces-service.test.ts
|
||||
# Expected: 2 added, 17 removed; one test file.
|
||||
git worktree add --detach "$replay_dir/worktree" "$candidate"
|
||||
git -C "$replay_dir/worktree" apply --reverse --check "$replay_dir/candidate.patch"
|
||||
```
|
||||
|
||||
Install the repository's pinned dependencies in the isolated worktree before
|
||||
running its owner suite. From that worktree's `server/`, run
|
||||
`node ../node_modules/vitest/vitest.mjs run --config vitest.config.ts src/__tests__/execution-workspaces-service.test.ts --reporter=default`.
|
||||
Reverse the candidate patch in that worktree to run the matching baseline, then
|
||||
apply it again and rerun the candidate. The integrated suite may contain more
|
||||
than the historical 67 cases; record its actual counts rather than substituting
|
||||
the historical numbers. Clean up only this replay worktree with
|
||||
`git worktree remove "$replay_dir/worktree"` and `rm -rf "$replay_dir"` after
|
||||
restoring any production mutation. The historical patch hash above does not
|
||||
claim to be the hash of this integrated patch.
|
||||
|
||||
## Mutation proof
|
||||
|
||||
The keeper is `reports a squash cross-branch delivery as merged_via_pr and suppresses the ancestry warning`. In `server/src/services/execution-workspaces.ts`, change the first condition in `deriveExecutionWorkspaceDeliveryState` from `input.sourceIssueTerminal && input.mergedPullRequest` to `input.sourceIssueTerminal && input.mergedPullRequest && input.isMergedIntoBase === true`. This rejects a valid squash/cross-branch PR. The keeper receives `unmerged` instead of `merged_via_pr`. In the full owner run this mutation produced 17 failures; the named keeper failed at candidate line 542. The mutation and candidate were restored byte-for-byte after proof.
|
||||
|
||||
Accepted phases were baseline 67/67, candidate 67/67, full revert 67/67, mutated owner 50 pass / 17 fail, and restored candidate 67/67, with zero skipped cases. The mutation controls production behavior; the PR changes tests only.
|
||||
|
||||
The proof replay finished during a stop attempt after a runtime-lane reservation arrived. It may have overlapped that lane's non-database test process. No host-wide serialization or CI-time savings are claimed. Proof source hashes, AST comparison, reports, and logs remain in the isolated audit workspace and are not represented as checked-in files.
|
||||
@@ -0,0 +1,55 @@
|
||||
# Worktree configuration fixture audit receipt
|
||||
|
||||
Date: 2026-10-13
|
||||
Base: `origin/codex/test-audit-r17-agent-instructions-module-reuse` at `97e65c60b665123ca51941293c70b546a74e4476` (PR #16171).
|
||||
Owner: `server/src/__tests__/worktree-config.test.ts`.
|
||||
|
||||
## Decision and scope
|
||||
|
||||
Replace five repeated configuration literals with local `buildLegacyConfig` results and explicit database/server port overrides. This is test setup de-duplication. No cases, assertions, persistence calls, file writes, or environment isolation are removed. Production files are unchanged. No runtime or CI speed improvement is claimed.
|
||||
|
||||
The original expression ranges are 396–417, 713–757, 776–797, 833–877, and 923–967. They protect sibling port avoidance, duplicate-port rebalancing, explicit-port auth URL updates, and no-port public auth URL preservation. Each fixture retains backups enabled. The first three keep the helper's default auth URL, including port 3100, while their server port remains 3101. The last two retain their explicit auth URLs. `buildIsolatedConfig` is unsuitable here because it disables backups and derives the auth port from the server port.
|
||||
|
||||
The transient-home expression at original lines 602–646 remains inline and byte-identical. Its path layout is intentionally different from the other fixtures.
|
||||
|
||||
## Evidence
|
||||
|
||||
Read the full owner suite, production `worktree-config.ts`, caller references in `config.ts`/`index.ts`, the shared Vitest setup, server Vitest configuration, stable test routing, and recent owner history. The production owner performs real config/env writes, worktree port reservations, and auth URL updates. Every owner regression remains in this suite; no replacement proof or test-only production seam is needed.
|
||||
|
||||
The five baseline and candidate expressions were evaluated using the unchanged helper and representative root values. Their actual `JSON.stringify(value, null, 2) + "\n"` outputs were byte-identical in all five comparisons. Backup flags, auth URLs, server ports, and database ports were preserved. Masking only the five expressions and removing their five new local declarations left all remaining source bytes identical. SHA-256 of that remaining source: `7e7c4299674671b032b2a6dd3242992bae8b5e695202769e1213c19e0132d40f`.
|
||||
|
||||
## Validation and cost
|
||||
|
||||
Existing dependency directories were linked into the isolated worktree without changing shared dependency installs. Baseline finished before candidate edits.
|
||||
|
||||
Command: `node_modules/.bin/vitest run --project @paperclipai/server server/src/__tests__/worktree-config.test.ts --silent=true`.
|
||||
|
||||
- Baseline: 1 file passed, 16/16 tests passed, duration 1.47s.
|
||||
- Candidate: 1 file passed, 16/16 tests passed, duration 1.43s.
|
||||
- Serialized fixture comparisons: 5/5 byte-identical.
|
||||
- Remaining-source comparison: identical, including the transient-home fixture.
|
||||
- `git diff --check`: passed.
|
||||
- Final diff review: no behavior change found outside the audited setup.
|
||||
|
||||
One local observation per version does not establish a timing benefit. Repository-wide typecheck, test, and build were not run locally for this bounded test-only setup change; broad PR checks remain pending. No merge-readiness claim is made.
|
||||
|
||||
## Counts and retained proof
|
||||
|
||||
Production LOC: 0 added, 0 removed. Test LOC: 20 added, 139 removed, net 119 removed. Test file: 1111 → 992 lines. Cases: 16 → 16. The receipt is documentation, counted separately from test LOC.
|
||||
|
||||
- repairs legacy repo-local worktree config and env files into an isolated instance
|
||||
- disables backups in an otherwise isolated existing worktree config
|
||||
- preserves an externally supplied PORT while repairing worktree config
|
||||
- never rewrites a main-instance env when ambient worktree flags leak into the process
|
||||
- does not persist runtime ports into a main-instance config when ambient worktree flags leak in
|
||||
- does not adopt a .paperclip config whose own env does not declare a worktree
|
||||
- avoids sibling worktree ports when repairing legacy configs
|
||||
- serializes and persists cross-repo worktree port reservations
|
||||
- ignores stale migrated env paths when the dev runner resolved the local config
|
||||
- does not persist transient runtime home overrides over repo-local worktree env
|
||||
- rebalances duplicate ports for already isolated worktree configs
|
||||
- persists runtime-selected worktree ports back into explicit-port auth URLs
|
||||
- does not rewrite no-port public auth URLs when persisting runtime-selected ports
|
||||
- preserves top-level and nested config extensions while persisting runtime ports
|
||||
- can update the in-memory config when auth URL already includes a port
|
||||
- does not rewrite the in-memory config when auth URL has no explicit port
|
||||
@@ -330,6 +330,12 @@ the initiator, reason, and recording time. Recorded stop intent survives adapter
|
||||
completion. `controller_lease` means the host stopped its own legacy adapter
|
||||
after it lost the durable controller lease; the reason names a closed cause
|
||||
(`renewal_rejected`, `renewal_deadline`, or `renewal_error`).
|
||||
A lease lost during run setup (for example a rejected renewal while preparing
|
||||
the workspace) settles the run `failed` with error code `controller_lease_lost`,
|
||||
the same `controller_lease` cancellation evidence, and
|
||||
`executionRecovery.providerWorkStarted: false`. Recovery retries it as transient
|
||||
infrastructure instead of blocking on `setup_failed`. A setup-phase error after
|
||||
provider dispatch began keeps `setup_failed`, so started work is never retried.
|
||||
The local lifecycle event includes this evidence. Started cancellations without
|
||||
an expected stop are also reported to Sentry; its cancellation diagnostics contain
|
||||
only source, expectedness, initiator type, and the closed lease-loss cause, never
|
||||
|
||||
@@ -5302,10 +5302,17 @@ describe("ACPX engine sandbox-start spans (opt-in root + child parenting)", () =
|
||||
const runRootSpan = roots[0]!;
|
||||
expect(runRootSpan.name).toBe("task.run");
|
||||
expect(runRootSpan.ended).toBe(true);
|
||||
expect(spans.filter((span) => span.name === "task.run")).toHaveLength(1);
|
||||
expect(runRootSpan.parentContextArg).toBeUndefined();
|
||||
expect(runRootSpan.endCalls).toBe(1);
|
||||
expect(runRootSpan.status).toBeNull();
|
||||
expect(runRootSpan.attributes["paperclip.task.run.run_id"]).toMatch(/^[0-9a-f]{12}$/);
|
||||
expect(String(runRootSpan.attributes["paperclip.task.run.run_id"])).not.toContain("run-");
|
||||
|
||||
// The sandbox bring-up span parents to the run root span.
|
||||
const startupSpan = spans.find((span) => span.name === "sandbox.startup");
|
||||
expect(startupSpan).toBeTruthy();
|
||||
expect(startupSpan!.parentContextArg).toEqual({ span: runRootSpan });
|
||||
expect(startupSpan!.parent).toBe(runRootSpan);
|
||||
expect(startupSpan!.ended).toBe(true);
|
||||
|
||||
@@ -5313,8 +5320,12 @@ describe("ACPX engine sandbox-start spans (opt-in root + child parenting)", () =
|
||||
// run root span, not to the bring-up span.
|
||||
const turnSpan = spans.find((span) => span.name === "agent.turn");
|
||||
expect(turnSpan).toBeTruthy();
|
||||
expect(spans.filter((span) => span.name === "agent.turn")).toHaveLength(1);
|
||||
expect(turnSpan!.parentContextArg).toEqual({ span: runRootSpan });
|
||||
expect(turnSpan!.parent).toBe(runRootSpan);
|
||||
expect(turnSpan!.ended).toBe(true);
|
||||
expect(turnSpan!.endCalls).toBe(1);
|
||||
expect(turnSpan!.status).toBeNull();
|
||||
|
||||
// The settlement sync-back opens the `sandbox.syncBack` span. It runs at
|
||||
// teardown, so it parents to the run root span, not to the bring-up span.
|
||||
@@ -5393,158 +5404,6 @@ describe("ACPX engine sandbox-start spans (opt-in root + child parenting)", () =
|
||||
}
|
||||
});
|
||||
|
||||
it("test_task_run_span_opens_and_ends_once_for_remote", async () => {
|
||||
const root = await makeTempRoot();
|
||||
const stateDir = path.join(root, "state");
|
||||
const localCwd = path.join(root, "worktree");
|
||||
const codexHome = path.join(root, "codex-home");
|
||||
await fs.mkdir(localCwd, { recursive: true });
|
||||
await fs.mkdir(codexHome, { recursive: true });
|
||||
const executionTarget = await remoteSandboxTarget(root);
|
||||
const { traceContext, spans } = createRecordingStartupTrace();
|
||||
|
||||
// Run the executor with a fake remote-sandbox tracer. The engine opens one
|
||||
// `task.run` root span and ends it once at the run return.
|
||||
await runExecutor(
|
||||
{
|
||||
agent: "codex",
|
||||
agentCommand: "node ./fake-acp.js",
|
||||
stateDir,
|
||||
cwd: localCwd,
|
||||
env: { CODEX_HOME: codexHome },
|
||||
},
|
||||
{ authToken: "real-run-jwt", executionTarget, startupTraceContext: traceContext },
|
||||
);
|
||||
|
||||
// Exactly one `task.run` span opens for a remote-sandbox run.
|
||||
const runSpans = spans.filter((span) => span.name === "task.run");
|
||||
expect(runSpans).toHaveLength(1);
|
||||
const runSpan = runSpans[0]!;
|
||||
// It is the trace root: it opens with no parent-context token.
|
||||
expect(runSpan.parent).toBeNull();
|
||||
expect(runSpan.parentContextArg).toBeUndefined();
|
||||
// It ends exactly once. A clean run sets no error status.
|
||||
expect(runSpan.ended).toBe(true);
|
||||
expect(runSpan.endCalls).toBe(1);
|
||||
expect(runSpan.status).toBeNull();
|
||||
// The run id rides only as a non-reversible hash; the raw run id never rides
|
||||
// the span.
|
||||
expect(runSpan.attributes["paperclip.task.run.run_id"]).toMatch(/^[0-9a-f]{12}$/);
|
||||
expect(String(runSpan.attributes["paperclip.task.run.run_id"])).not.toContain("run-");
|
||||
});
|
||||
|
||||
it("test_sandbox_startup_parents_to_task_run", async () => {
|
||||
const root = await makeTempRoot();
|
||||
const stateDir = path.join(root, "state");
|
||||
const localCwd = path.join(root, "worktree");
|
||||
const codexHome = path.join(root, "codex-home");
|
||||
await fs.mkdir(localCwd, { recursive: true });
|
||||
await fs.mkdir(codexHome, { recursive: true });
|
||||
const executionTarget = await remoteSandboxTarget(root);
|
||||
const { traceContext, spans } = createRecordingStartupTrace();
|
||||
|
||||
// Run the executor startup path with a fake remote-sandbox tracer. The run
|
||||
// root opens the `task.run` span first, then the startup root opens the
|
||||
// `sandbox.startup` span as its child.
|
||||
await runExecutor(
|
||||
{
|
||||
agent: "codex",
|
||||
agentCommand: "node ./fake-acp.js",
|
||||
stateDir,
|
||||
cwd: localCwd,
|
||||
env: { CODEX_HOME: codexHome },
|
||||
},
|
||||
{ authToken: "real-run-jwt", executionTarget, startupTraceContext: traceContext },
|
||||
);
|
||||
|
||||
const runSpan = spans.find((span) => span.name === "task.run");
|
||||
expect(runSpan).toBeTruthy();
|
||||
const startupSpan = spans.find((span) => span.name === "sandbox.startup");
|
||||
expect(startupSpan).toBeTruthy();
|
||||
// The `sandbox.startup` `startSpan` call now receives the `task.run` parent
|
||||
// context as its third argument. The recorder builds the token as
|
||||
// `{ span }`, so the token carries the run span and the startup span parents
|
||||
// to `task.run`.
|
||||
expect(startupSpan!.parentContextArg).toEqual({ span: runSpan });
|
||||
expect(startupSpan!.parent).toBe(runSpan);
|
||||
});
|
||||
|
||||
it("test_task_run_span_is_noop_for_local_target", async () => {
|
||||
const root = await makeTempRoot();
|
||||
const stateDir = path.join(root, "state");
|
||||
const localCwd = path.join(root, "worktree");
|
||||
await fs.mkdir(localCwd, { recursive: true });
|
||||
const { traceContext, spans } = createRecordingStartupTrace();
|
||||
|
||||
// A local run has no sandbox, so the run root span stays a no-op even when a
|
||||
// trace context is injected. No real `task.run` span opens.
|
||||
const { result } = await runExecutor(
|
||||
{ agent: "custom", agentCommand: "node ./fake-acp.js", stateDir, cwd: localCwd },
|
||||
{ authToken: "real-run-jwt", startupTraceContext: traceContext },
|
||||
);
|
||||
expect(result.exitCode).toBe(0);
|
||||
expect(spans.some((span) => span.name === "task.run")).toBe(false);
|
||||
expect(spans).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("test_agent_turn_span_parents_to_task_run", async () => {
|
||||
const root = await makeTempRoot();
|
||||
const stateDir = path.join(root, "state");
|
||||
const localCwd = path.join(root, "worktree");
|
||||
const codexHome = path.join(root, "codex-home");
|
||||
await fs.mkdir(localCwd, { recursive: true });
|
||||
await fs.mkdir(codexHome, { recursive: true });
|
||||
const executionTarget = await remoteSandboxTarget(root);
|
||||
const { traceContext, spans } = createRecordingStartupTrace();
|
||||
|
||||
// Run the executor turn path with a fake remote-sandbox tracer. The engine
|
||||
// opens one `agent.turn` span around the turn as a child of `task.run` and
|
||||
// ends it once at the turn return.
|
||||
await runExecutor(
|
||||
{
|
||||
agent: "codex",
|
||||
agentCommand: "node ./fake-acp.js",
|
||||
stateDir,
|
||||
cwd: localCwd,
|
||||
env: { CODEX_HOME: codexHome },
|
||||
},
|
||||
{ authToken: "real-run-jwt", executionTarget, startupTraceContext: traceContext },
|
||||
);
|
||||
|
||||
const runSpan = spans.find((span) => span.name === "task.run");
|
||||
expect(runSpan).toBeTruthy();
|
||||
// Exactly one `agent.turn` span opens for a remote-sandbox run.
|
||||
const turnSpans = spans.filter((span) => span.name === "agent.turn");
|
||||
expect(turnSpans).toHaveLength(1);
|
||||
const turnSpan = turnSpans[0]!;
|
||||
// The `agent.turn` `startSpan` call receives the `task.run` parent context
|
||||
// as its third argument. The recorder builds the token as `{ span }`, so the
|
||||
// turn span parents to `task.run`.
|
||||
expect(turnSpan.parentContextArg).toEqual({ span: runSpan });
|
||||
expect(turnSpan.parent).toBe(runSpan);
|
||||
// It ends exactly once. A clean turn sets no error status.
|
||||
expect(turnSpan.ended).toBe(true);
|
||||
expect(turnSpan.endCalls).toBe(1);
|
||||
expect(turnSpan.status).toBeNull();
|
||||
});
|
||||
|
||||
it("test_agent_turn_span_is_noop_for_local_target", async () => {
|
||||
const root = await makeTempRoot();
|
||||
const stateDir = path.join(root, "state");
|
||||
const localCwd = path.join(root, "worktree");
|
||||
await fs.mkdir(localCwd, { recursive: true });
|
||||
const { traceContext, spans } = createRecordingStartupTrace();
|
||||
|
||||
// A local run has no sandbox, so the turn span stays a no-op even when a
|
||||
// trace context is injected. No real `agent.turn` span opens.
|
||||
const { result } = await runExecutor(
|
||||
{ agent: "custom", agentCommand: "node ./fake-acp.js", stateDir, cwd: localCwd },
|
||||
{ authToken: "real-run-jwt", startupTraceContext: traceContext },
|
||||
);
|
||||
expect(result.exitCode).toBe(0);
|
||||
expect(spans.some((span) => span.name === "agent.turn")).toBe(false);
|
||||
});
|
||||
|
||||
it("test_run_parent_getter_tracks_task_run_then_turn", async () => {
|
||||
const root = await makeTempRoot();
|
||||
const stateDir = path.join(root, "state");
|
||||
@@ -5620,105 +5479,6 @@ describe("ACPX engine sandbox-start spans (opt-in root + child parenting)", () =
|
||||
expect(postToken).toEqual({ span: taskRunSpan });
|
||||
});
|
||||
|
||||
it("test_root_region_exec_parents_to_sandbox_startup", async () => {
|
||||
const root = await makeTempRoot();
|
||||
const stateDir = path.join(root, "state");
|
||||
const localCwd = path.join(root, "worktree");
|
||||
const codexHome = path.join(root, "codex-home");
|
||||
await fs.mkdir(localCwd, { recursive: true });
|
||||
await fs.mkdir(codexHome, { recursive: true });
|
||||
const executionTarget = await remoteSandboxTarget(root);
|
||||
const { traceContext, spans } = createRecordingStartupTrace();
|
||||
|
||||
// Issue one exec from the root region of the bring-up. `getServers()` runs
|
||||
// once inside the bring-up, after the `sandbox.startup` span opens and
|
||||
// outside every measured step, so it stands in for a startup-body exec that
|
||||
// runs at the root region. The run publishes the `sandbox.startup` context to
|
||||
// the runtime-parent store for the whole bring-up, so the exec reads that
|
||||
// token here.
|
||||
const runtimeMcp = {
|
||||
getServers: () => {
|
||||
issueSandboxExecFromStore(traceContext);
|
||||
return [];
|
||||
},
|
||||
};
|
||||
|
||||
await runExecutor(
|
||||
{
|
||||
agent: "codex",
|
||||
agentCommand: "node ./fake-acp.js",
|
||||
stateDir,
|
||||
cwd: localCwd,
|
||||
env: { CODEX_HOME: codexHome },
|
||||
},
|
||||
{
|
||||
authToken: "real-run-jwt",
|
||||
executionTarget,
|
||||
startupTraceContext: traceContext,
|
||||
runtimeMcp: runtimeMcp as never,
|
||||
},
|
||||
);
|
||||
|
||||
const startupSpan = spans.find((span) => span.name === "sandbox.startup");
|
||||
expect(startupSpan).toBeTruthy();
|
||||
const execSpan = spans.find((span) => span.name === "sandbox.exec");
|
||||
expect(execSpan).toBeTruthy();
|
||||
// The root-region exec parents to `sandbox.startup`, not to a detached root.
|
||||
// The third `startSpan` argument is the exact `sandbox.startup` child context
|
||||
// that `contextWithSpan` built, so the exec span is a child of the bring-up.
|
||||
expect(execSpan!.parentContextArg).toEqual({ span: startupSpan });
|
||||
expect(execSpan!.parent).toBe(startupSpan);
|
||||
});
|
||||
|
||||
it("test_in_step_exec_still_parents_to_step_after_root_wrap", async () => {
|
||||
const root = await makeTempRoot();
|
||||
const stateDir = path.join(root, "state");
|
||||
const localCwd = path.join(root, "worktree");
|
||||
const codexHome = path.join(root, "codex-home");
|
||||
await fs.mkdir(localCwd, { recursive: true });
|
||||
await fs.mkdir(codexHome, { recursive: true });
|
||||
const executionTarget = await remoteSandboxTarget(root);
|
||||
const { traceContext, spans } = createRecordingStartupTrace();
|
||||
|
||||
// Issue one exec from inside the `stage.sync` step body, under the same root
|
||||
// wrap. `prepareRemoteManagedHome` runs inside the measured `stage.sync`
|
||||
// step, so the step overrides the runtime-parent store with its own context
|
||||
// there. The in-step exec must read the step context, not the root context.
|
||||
await runExecutor(
|
||||
{
|
||||
agent: "codex",
|
||||
agentCommand: "node ./fake-acp.js",
|
||||
stateDir,
|
||||
cwd: localCwd,
|
||||
env: { CODEX_HOME: codexHome },
|
||||
},
|
||||
{
|
||||
authToken: "real-run-jwt",
|
||||
executionTarget,
|
||||
startupTraceContext: traceContext,
|
||||
prepareRemoteManagedHome: async (input) => {
|
||||
issueSandboxExecFromStore(traceContext);
|
||||
const stagedRuntime = await input.stage([]);
|
||||
return { stagedRuntime };
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const stepSpan = spans.find((span) => span.name === "stage.sync");
|
||||
expect(stepSpan).toBeTruthy();
|
||||
const startupSpan = spans.find((span) => span.name === "sandbox.startup");
|
||||
expect(startupSpan).toBeTruthy();
|
||||
const execSpan = spans.find((span) => span.name === "sandbox.exec");
|
||||
expect(execSpan).toBeTruthy();
|
||||
// The in-step exec still parents to its step span. `measureStartupStep`
|
||||
// overrides the store inside the wrap, so the step context wins over the
|
||||
// root context for an exec that runs inside the step.
|
||||
expect(execSpan!.parentContextArg).toEqual({ span: stepSpan });
|
||||
expect(execSpan!.parent).toBe(stepSpan);
|
||||
// The in-step exec does not parent to `sandbox.startup`.
|
||||
expect(execSpan!.parent).not.toBe(startupSpan);
|
||||
});
|
||||
|
||||
it("records root wall / work / diff times and the bounded context on the root span", async () => {
|
||||
const root = await makeTempRoot();
|
||||
const stateDir = path.join(root, "state");
|
||||
@@ -5804,54 +5564,6 @@ describe("ACPX engine sandbox-start spans (opt-in root + child parenting)", () =
|
||||
expect(rootSpan!.attributes[A.rootWorkMs]).toBe(sumExceptReconcile);
|
||||
});
|
||||
|
||||
it("parents both concurrent bridge spans to the root (neither orphans)", async () => {
|
||||
const root = await makeTempRoot();
|
||||
const stateDir = path.join(root, "state");
|
||||
const localCwd = path.join(root, "worktree");
|
||||
await fs.mkdir(localCwd, { recursive: true });
|
||||
const executionTarget = await remoteSandboxTarget(root);
|
||||
const { traceContext, spans } = createRecordingStartupTrace();
|
||||
|
||||
await runExecutor(
|
||||
{ agent: "custom", agentCommand: "node ./fake-acp.js", stateDir, cwd: localCwd },
|
||||
{ authToken: "real-run-jwt", executionTarget, startupTraceContext: traceContext },
|
||||
);
|
||||
|
||||
const rootSpan = spans.find((span) => span.name === "sandbox.startup");
|
||||
expect(rootSpan).toBeTruthy();
|
||||
const paperclip = spans.find((span) => span.name === "bridge.paperclip");
|
||||
const processSession = spans.find((span) => span.name === "bridge.process-session");
|
||||
expect(paperclip?.parent).toBe(rootSpan);
|
||||
expect(processSession?.parent).toBe(rootSpan);
|
||||
// Both bridge spans carry the same batch tag, so the trace marks them as one
|
||||
// parallel batch.
|
||||
expect(paperclip?.attributes[A.batch]).toBe("bridge");
|
||||
expect(processSession?.attributes[A.batch]).toBe("bridge");
|
||||
expect(paperclip?.attributes[A.batch]).toBe(processSession?.attributes[A.batch]);
|
||||
});
|
||||
|
||||
it("records the handshake create-runtime and ensure-session sub-times on the acp.handshake span", async () => {
|
||||
const root = await makeTempRoot();
|
||||
const stateDir = path.join(root, "state");
|
||||
const localCwd = path.join(root, "worktree");
|
||||
await fs.mkdir(localCwd, { recursive: true });
|
||||
const executionTarget = await remoteSandboxTarget(root);
|
||||
const { traceContext, spans } = createRecordingStartupTrace();
|
||||
|
||||
await runExecutor(
|
||||
{ agent: "custom", agentCommand: "node ./fake-acp.js", stateDir, cwd: localCwd },
|
||||
{ authToken: "real-run-jwt", executionTarget, startupTraceContext: traceContext },
|
||||
);
|
||||
|
||||
const handshake = spans.find((span) => span.name === "acp.handshake");
|
||||
expect(handshake).toBeTruthy();
|
||||
// A cold start records both sub-times as finite float ms on the span.
|
||||
expect(typeof handshake!.attributes[A.handshakeCreateRuntimeWallMs]).toBe("number");
|
||||
expect(handshake!.attributes[A.handshakeCreateRuntimeWallMs] as number).toBeGreaterThanOrEqual(0);
|
||||
expect(typeof handshake!.attributes[A.handshakeEnsureSessionWallMs]).toBe("number");
|
||||
expect(handshake!.attributes[A.handshakeEnsureSessionWallMs] as number).toBeGreaterThanOrEqual(0);
|
||||
});
|
||||
|
||||
it("keeps every span attribute inside the closed allowlist (no command/path/id keys)", async () => {
|
||||
const root = await makeTempRoot();
|
||||
const stateDir = path.join(root, "state");
|
||||
@@ -5886,6 +5598,26 @@ describe("ACPX engine sandbox-start spans (opt-in root + child parenting)", () =
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const rootSpan = spans.find((span) => span.name === "sandbox.startup");
|
||||
expect(rootSpan).toBeTruthy();
|
||||
const paperclip = spans.find((span) => span.name === "bridge.paperclip");
|
||||
const processSession = spans.find((span) => span.name === "bridge.process-session");
|
||||
expect(paperclip?.parent).toBe(rootSpan);
|
||||
expect(processSession?.parent).toBe(rootSpan);
|
||||
// Both bridge spans carry the same batch tag, so the trace marks them as one
|
||||
// parallel batch.
|
||||
expect(paperclip?.attributes[A.batch]).toBe("bridge");
|
||||
expect(processSession?.attributes[A.batch]).toBe("bridge");
|
||||
expect(paperclip?.attributes[A.batch]).toBe(processSession?.attributes[A.batch]);
|
||||
|
||||
const handshake = spans.find((span) => span.name === "acp.handshake");
|
||||
expect(handshake).toBeTruthy();
|
||||
// A cold start records both sub-times as finite float ms on the span.
|
||||
expect(typeof handshake!.attributes[A.handshakeCreateRuntimeWallMs]).toBe("number");
|
||||
expect(handshake!.attributes[A.handshakeCreateRuntimeWallMs] as number).toBeGreaterThanOrEqual(0);
|
||||
expect(typeof handshake!.attributes[A.handshakeEnsureSessionWallMs]).toBe("number");
|
||||
expect(handshake!.attributes[A.handshakeEnsureSessionWallMs] as number).toBeGreaterThanOrEqual(0);
|
||||
});
|
||||
|
||||
it("closes the root span with error status when the bring-up handshake fails", async () => {
|
||||
@@ -6112,10 +5844,12 @@ describe("ACPX engine sandbox-start spans (opt-in root + child parenting)", () =
|
||||
// A root-region exec parents to `sandbox.startup`.
|
||||
const rootRegionExec = execSpans.find((span) => span.parent === startupSpan);
|
||||
expect(rootRegionExec, "a root-region exec must parent to sandbox.startup").toBeTruthy();
|
||||
expect(rootRegionExec!.parentContextArg).toEqual({ span: startupSpan });
|
||||
|
||||
// A `stage.sync` body exec parents to the sync step, not to `sandbox.startup`.
|
||||
const syncExec = execSpans.find((span) => span.parent === syncStepSpan);
|
||||
expect(syncExec, "a stage.sync exec must parent to the sync step").toBeTruthy();
|
||||
expect(syncExec!.parentContextArg).toEqual({ span: syncStepSpan });
|
||||
expect(syncExec!.parent).not.toBe(startupSpan);
|
||||
|
||||
// A turn detached exec parents to `agent.turn`.
|
||||
|
||||
@@ -464,15 +464,14 @@ describe("command managed runtime", () => {
|
||||
cleanupDirs.push(rootDir);
|
||||
const remotePath = path.join(rootDir, "nested", "payload.bin");
|
||||
|
||||
// ~3 MB of every byte value so the test catches any non-binary-safe handling.
|
||||
const payload = Buffer.alloc(3 * 1024 * 1024);
|
||||
const payload = Buffer.alloc(9 * 1024 * 1024);
|
||||
for (let i = 0; i < payload.length; i++) payload[i] = i % 256;
|
||||
|
||||
const { runner, calls } = makeSpawnRunner({ supportsSingleStreamStdinProgress: true });
|
||||
const client = createCommandManagedRuntimeClient({ runner, commandCwd: "/", timeoutMs: 30_000 });
|
||||
|
||||
const progress: Array<{ done: number; total: number | null }> = [];
|
||||
await withBase64StringByteLimit(4 * 1024 * 1024, async () => {
|
||||
await withBase64StringByteLimit(9 * 1024 * 1024, async () => {
|
||||
await client.writeFile(remotePath, toArrayBuffer(payload), {
|
||||
onProgress: (done, total) => {
|
||||
progress.push({ done, total });
|
||||
@@ -918,30 +917,6 @@ describe("command managed runtime", () => {
|
||||
expect(executed.some((s) => s.includes("SHOULD-NOT-RUN"))).toBe(false);
|
||||
});
|
||||
|
||||
it("test_single_stream_writeFile_collapses_roundtrips_under_96MiB", async () => {
|
||||
// Research A1: with single-stream enabled a ≤96 MiB write is ONE round-trip;
|
||||
// without it, the chunked path is `2 + ceil(bytes / 3 MiB)`. Same payload,
|
||||
// same client API — only the runner capability flag differs.
|
||||
const rootDir = await mkdtemp(path.join(os.tmpdir(), "paperclip-single-stream-collapse-"));
|
||||
cleanupDirs.push(rootDir);
|
||||
const payload = Buffer.alloc(9 * 1024 * 1024, 7); // 9 MiB → chunked = 2 + 3 = 5 execs
|
||||
|
||||
const single = makeSpawnRunner({ supportsSingleStreamStdinProgress: true });
|
||||
const singleClient = createCommandManagedRuntimeClient({ runner: single.runner, commandCwd: "/", timeoutMs: 30_000 });
|
||||
await singleClient.writeFile(path.join(rootDir, "single.bin"), toArrayBuffer(payload));
|
||||
expect(single.calls.length).toBe(2);
|
||||
|
||||
const chunked = makeSpawnRunner({ supportsSingleStreamStdinProgress: false });
|
||||
const chunkedClient = createCommandManagedRuntimeClient({ runner: chunked.runner, commandCwd: "/", timeoutMs: 30_000 });
|
||||
await chunkedClient.writeFile(path.join(rootDir, "chunked.bin"), toArrayBuffer(payload));
|
||||
// 3 (init temp + final mv + cleanup) + ceil(9MiB / 3MiB) = 6 round-trips.
|
||||
expect(chunked.calls.length).toBe(3 + Math.ceil(payload.byteLength / (3 * 1024 * 1024)));
|
||||
expect(chunked.calls.length).toBeGreaterThan(single.calls.length);
|
||||
|
||||
expect((await readFile(path.join(rootDir, "single.bin"))).equals(payload)).toBe(true);
|
||||
expect((await readFile(path.join(rootDir, "chunked.bin"))).equals(payload)).toBe(true);
|
||||
});
|
||||
|
||||
it("falls back to chunked upload progress when the runner cannot report mid-stream stdin progress", async () => {
|
||||
const rootDir = await mkdtemp(path.join(os.tmpdir(), "paperclip-command-write-fallback-"));
|
||||
cleanupDirs.push(rootDir);
|
||||
@@ -965,7 +940,7 @@ describe("command managed runtime", () => {
|
||||
|
||||
// Provider-backed sandbox runners cannot surface mid-flight progress for a
|
||||
// single stdin RPC, so we intentionally use several large append commands.
|
||||
expect(calls.length).toBeGreaterThan(2);
|
||||
expect(calls.length).toBe(3 + Math.ceil(payload.byteLength / (3 * 1024 * 1024)));
|
||||
const stdinCalls = calls.filter((call) => call.stdin != null);
|
||||
expect(stdinCalls.length).toBeGreaterThan(2);
|
||||
expect(stdinCalls.every((call) => Buffer.byteLength(call.stdin ?? "", "utf8") <= 4.1 * 1024 * 1024)).toBe(true);
|
||||
|
||||
@@ -4576,6 +4576,7 @@ describe("sandbox adapter execution targets", () => {
|
||||
const target: AdapterSandboxExecutionTarget = duplexSandboxTarget(remoteCwd, runner);
|
||||
|
||||
__duplexReadinessTesting.resetNewlineScanUnits();
|
||||
__duplexReadinessTesting.resetBufferGrowthCopyUnits();
|
||||
const bridge = await startTestDuplexBridge("run-scan-bound", target, api.origin, {
|
||||
duplexReadinessTimeoutMs: 5_000,
|
||||
duplexObservabilityRecorder: recorder,
|
||||
@@ -4588,45 +4589,7 @@ describe("sandbox adapter execution targets", () => {
|
||||
// totalBytes. A per-chunk full rescan is quadratic (about
|
||||
// totalBytes^2 / (2 * chunkSize)), far above this bound.
|
||||
expect(scanUnits).toBeLessThanOrEqual(4 * totalBytes);
|
||||
} finally {
|
||||
await bridge?.stop();
|
||||
await api.close();
|
||||
}
|
||||
}, 20000);
|
||||
|
||||
it("bounds the pre-READY buffer growth-copy work by the bytes received", async () => {
|
||||
const { rootDir, remoteCwd } = await createSandboxWorkspace("paperclip-duplex-growth-");
|
||||
const api = await startRecordingApiServer();
|
||||
// An adversarial provider sends many small newline-less fragments before the
|
||||
// cap fires. A one-copy-per-fragment append copies the whole retained buffer
|
||||
// on every fragment, so the total copy work is quadratic in the number of
|
||||
// fragments. The gate must instead grow its backing storage by doubling, so
|
||||
// the total copy work stays linear in the bytes received.
|
||||
const readinessBufferCapBytes = DEFAULT_MAX_DUPLEX_FRAME_BYTES + 4_096;
|
||||
const smallChunk = "x".repeat(64);
|
||||
const chunkCount = Math.ceil(readinessBufferCapBytes / smallChunk.length) + 1;
|
||||
const totalBytes = chunkCount * smallChunk.length;
|
||||
const { runner, control } = makeDuplexSelectionRunner((ctx) => {
|
||||
for (let i = 0; i < chunkCount; i += 1) {
|
||||
ctx.emitRaw(smallChunk);
|
||||
}
|
||||
});
|
||||
const { recorder } = createRecordingDuplexRecorder();
|
||||
const target: AdapterSandboxExecutionTarget = duplexSandboxTarget(remoteCwd, runner);
|
||||
|
||||
__duplexReadinessTesting.resetBufferGrowthCopyUnits();
|
||||
const bridge = await startTestDuplexBridge("run-growth-bound", target, api.origin, {
|
||||
duplexReadinessTimeoutMs: 5_000,
|
||||
duplexObservabilityRecorder: recorder,
|
||||
});
|
||||
try {
|
||||
expect(bridge).not.toBeNull();
|
||||
expect(control.openCount).toBe(1);
|
||||
const copyUnits = __duplexReadinessTesting.readBufferGrowthCopyUnits();
|
||||
// Doubling growth copies a logarithmic number of times, each at most the
|
||||
// current buffer length, so the total stays within a small multiple of
|
||||
// totalBytes. A per-fragment full-buffer copy is quadratic (about
|
||||
// totalBytes^2 / (2 * chunkSize)), far above this bound.
|
||||
expect(copyUnits).toBeLessThanOrEqual(4 * totalBytes);
|
||||
} finally {
|
||||
await bridge?.stop();
|
||||
|
||||
@@ -128,6 +128,11 @@ describe("device-login credential promotion", () => {
|
||||
log: noopLog,
|
||||
});
|
||||
expect(result.outcome).toBe("promoted");
|
||||
expect(result.accountId).toBe(ACCOUNT);
|
||||
expect(result.accountHomeDir).toBe(
|
||||
path.dirname(resolveCodexAuthCacheEntryPath(env, ACCOUNT, COMPANY_A)),
|
||||
);
|
||||
expect(result.accountHomeCreated).toBe(true);
|
||||
|
||||
const homeAuth = await readFile(companyHomeAuthPath(env, COMPANY_A), "utf8");
|
||||
expect(JSON.parse(homeAuth).tokens.account_id).toBe(ACCOUNT);
|
||||
@@ -229,40 +234,6 @@ describe("device-login credential promotion", () => {
|
||||
expect(otherAccountAuth.tokens.account_id).toBe(OTHER_ACCOUNT);
|
||||
});
|
||||
|
||||
it("promotion returns the account id and the account home path", async () => {
|
||||
const home = await makeInstanceRoot();
|
||||
const env = envFor(home);
|
||||
const result = await promoteDeviceLoginCredential({
|
||||
authBytes: subscriptionAuth({ accountId: ACCOUNT, lastRefresh: NEWER }),
|
||||
companyId: COMPANY_A,
|
||||
userInitiated: true,
|
||||
checkReadiness: ready,
|
||||
isSoleActiveOwner: soleOwner,
|
||||
env,
|
||||
log: noopLog,
|
||||
});
|
||||
expect(result.accountId).toBe(ACCOUNT);
|
||||
expect(result.accountHomeDir).toBe(
|
||||
path.dirname(resolveCodexAuthCacheEntryPath(env, ACCOUNT, COMPANY_A)),
|
||||
);
|
||||
});
|
||||
|
||||
it("promotion reports accountHomeCreated true for a first login of an account", async () => {
|
||||
const home = await makeInstanceRoot();
|
||||
const env = envFor(home);
|
||||
const result = await promoteDeviceLoginCredential({
|
||||
authBytes: subscriptionAuth({ accountId: ACCOUNT, lastRefresh: NEWER }),
|
||||
companyId: COMPANY_A,
|
||||
userInitiated: true,
|
||||
checkReadiness: ready,
|
||||
isSoleActiveOwner: soleOwner,
|
||||
env,
|
||||
log: noopLog,
|
||||
});
|
||||
expect(result.outcome).toBe("promoted");
|
||||
expect(result.accountHomeCreated).toBe(true);
|
||||
});
|
||||
|
||||
it("promotion reports accountHomeCreated false for a repeat login of the same account", async () => {
|
||||
const home = await makeInstanceRoot();
|
||||
const env = envFor(home);
|
||||
@@ -356,23 +327,6 @@ describe("device-login credential promotion", () => {
|
||||
expect(await readFile(companyHomeAuthPath(env, COMPANY_A), "utf8")).toBe(before);
|
||||
});
|
||||
|
||||
it("promotion seeds the company default home when it holds no usable credential", async () => {
|
||||
const home = await makeInstanceRoot();
|
||||
const env = envFor(home);
|
||||
const result = await promoteDeviceLoginCredential({
|
||||
authBytes: subscriptionAuth({ accountId: ACCOUNT, lastRefresh: NEWER }),
|
||||
companyId: COMPANY_A,
|
||||
userInitiated: true,
|
||||
checkReadiness: ready,
|
||||
isSoleActiveOwner: soleOwner,
|
||||
env,
|
||||
log: noopLog,
|
||||
});
|
||||
expect(result.outcome).toBe("promoted");
|
||||
const homeAuth = await readFile(companyHomeAuthPath(env, COMPANY_A), "utf8");
|
||||
expect(JSON.parse(homeAuth).tokens.account_id).toBe(ACCOUNT);
|
||||
});
|
||||
|
||||
it("a strictly-newer same-account login refreshes the company default home", async () => {
|
||||
// The sign-in loop this pins: a company home already holding a shape-usable
|
||||
// credential for this account must still pick up the login the user just
|
||||
|
||||
@@ -104,23 +104,6 @@ describe("codex-auth-merge-decision predicate seed mode", () => {
|
||||
}
|
||||
}
|
||||
|
||||
it("default mode keeps destination when destination is absent (host-default fail-closed)", async () => {
|
||||
const code = await runDecision({
|
||||
sourceAuth: subscriptionAuth({ accountId: "acct", lastRefresh: NEWER }),
|
||||
destinationAuth: ABSENT,
|
||||
});
|
||||
expect(code).toBe(KEEP_DESTINATION);
|
||||
});
|
||||
|
||||
it("seed mode uses source when destination is absent and source is a usable subscription credential", async () => {
|
||||
const code = await runDecision({
|
||||
seed: true,
|
||||
sourceAuth: subscriptionAuth({ accountId: "acct", lastRefresh: NEWER }),
|
||||
destinationAuth: ABSENT,
|
||||
});
|
||||
expect(code).toBe(USE_SOURCE);
|
||||
});
|
||||
|
||||
it("seed mode uses source when destination is unparseable and source is a usable subscription credential", async () => {
|
||||
const code = await runDecision({
|
||||
seed: true,
|
||||
|
||||
@@ -1102,6 +1102,12 @@ describe("stageCodexHomeForSync", () => {
|
||||
const { home, authBytes, skillBytes } = await buildFakeHome(root);
|
||||
staged = await stageCodexHomeForSync(home, { runId: "run-1" });
|
||||
|
||||
expect((await fs.stat(staged)).mode & 0o777).toBe(0o700);
|
||||
for (const entry of ["auth.json", "config.toml", "config.json", "instructions.md"]) {
|
||||
const mode = (await fs.stat(path.join(staged, entry))).mode & 0o777;
|
||||
expect(mode, `${entry} should be staged 0600`).toBe(0o600);
|
||||
}
|
||||
|
||||
const entries = (await fs.readdir(staged)).sort();
|
||||
expect(entries).toEqual([...CODEX_SYNC_ALLOWLIST].sort());
|
||||
|
||||
@@ -1128,21 +1134,6 @@ describe("stageCodexHomeForSync", () => {
|
||||
}
|
||||
});
|
||||
|
||||
// C1 — staged credential file must be mode 0600 (not the world-readable default).
|
||||
it("writes the staged auth.json with mode 0600", async () => {
|
||||
const root = await fs.mkdtemp(path.join(os.tmpdir(), "paperclip-codex-stage-mode-"));
|
||||
let staged: string | null = null;
|
||||
try {
|
||||
const { home } = await buildFakeHome(root);
|
||||
staged = await stageCodexHomeForSync(home, { runId: "run-mode" });
|
||||
const mode = (await fs.stat(path.join(staged, "auth.json"))).mode & 0o777;
|
||||
expect(mode).toBe(0o600);
|
||||
} finally {
|
||||
if (staged) await fs.rm(staged, { recursive: true, force: true });
|
||||
await fs.rm(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
// config.toml carries the managed MCP `Authorization: Bearer …` header and is
|
||||
// secret-bearing; the staged copy must be 0600, not the world-readable default.
|
||||
it("writes the staged config.toml (managed MCP bearer header) with mode 0600", async () => {
|
||||
@@ -1167,39 +1158,6 @@ describe("stageCodexHomeForSync", () => {
|
||||
}
|
||||
});
|
||||
|
||||
// Least privilege: no staged regular file needs group/other read, so every
|
||||
// one (config.json, instructions.md — not just credentials) is staged 0600.
|
||||
it("writes every staged regular file with mode 0600", async () => {
|
||||
const root = await fs.mkdtemp(path.join(os.tmpdir(), "paperclip-codex-stage-all-mode-"));
|
||||
let staged: string | null = null;
|
||||
try {
|
||||
const { home } = await buildFakeHome(root);
|
||||
staged = await stageCodexHomeForSync(home, { runId: "run-all-mode" });
|
||||
for (const entry of ["auth.json", "config.toml", "config.json", "instructions.md"]) {
|
||||
const mode = (await fs.stat(path.join(staged, entry))).mode & 0o777;
|
||||
expect(mode, `${entry} should be staged 0600`).toBe(0o600);
|
||||
}
|
||||
} finally {
|
||||
if (staged) await fs.rm(staged, { recursive: true, force: true });
|
||||
await fs.rm(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
// C2 — staged dir must be 0700 (mkdtemp guarantees this on POSIX).
|
||||
it("creates the staged dir with mode 0700", async () => {
|
||||
const root = await fs.mkdtemp(path.join(os.tmpdir(), "paperclip-codex-stage-dir-"));
|
||||
let staged: string | null = null;
|
||||
try {
|
||||
const { home } = await buildFakeHome(root);
|
||||
staged = await stageCodexHomeForSync(home, { runId: "run-dir" });
|
||||
const mode = (await fs.stat(staged)).mode & 0o777;
|
||||
expect(mode).toBe(0o700);
|
||||
} finally {
|
||||
if (staged) await fs.rm(staged, { recursive: true, force: true });
|
||||
await fs.rm(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("skips absent optional entries without throwing", async () => {
|
||||
const root = await fs.mkdtemp(path.join(os.tmpdir(), "paperclip-codex-stage-absent-"));
|
||||
let staged: string | null = null;
|
||||
|
||||
@@ -415,6 +415,9 @@ describe("grok device-login credential promotion", () => {
|
||||
const authPath = companyHomeAuthPath(env, COMPANY_A);
|
||||
const written = JSON.parse(await readFile(authPath, "utf8"));
|
||||
expect(written[`${ISSUER}::${UUID_A}`].refresh_token).toBe(`${TOKEN_SENTINEL}-fresher`);
|
||||
const companyHome = resolveManagedGrokHomeDir(env, COMPANY_A);
|
||||
const entries = await readdir(companyHome);
|
||||
expect(entries).toEqual(["auth.json"]);
|
||||
});
|
||||
|
||||
it("keeps the home when the login expiry ties the existing same-identity credential", async () => {
|
||||
@@ -446,34 +449,6 @@ describe("grok device-login credential promotion", () => {
|
||||
expect(written[`${ISSUER}::${UUID_A}`].refresh_token).toBe(`${TOKEN_SENTINEL}-first`);
|
||||
});
|
||||
|
||||
it("leaves no staged temporary file in the company home after a kept (not-fresher) outcome", async () => {
|
||||
const home = await makeInstanceRoot();
|
||||
const env = envFor(home);
|
||||
await promoteGrokDeviceLoginCredential({
|
||||
authBytes: grokAuth({ uuid: UUID_A, marker: "fresher", expiresAt: "2026-06-01T00:00:00Z" }),
|
||||
companyId: COMPANY_A,
|
||||
userInitiated: true,
|
||||
checkReadiness: ready,
|
||||
isSoleActiveOwner: soleOwner,
|
||||
env,
|
||||
log: noopLog,
|
||||
});
|
||||
|
||||
const outcome = await promoteGrokDeviceLoginCredential({
|
||||
authBytes: grokAuth({ uuid: UUID_A, marker: "staler", expiresAt: "2026-01-01T00:00:00Z" }),
|
||||
companyId: COMPANY_A,
|
||||
userInitiated: true,
|
||||
checkReadiness: ready,
|
||||
isSoleActiveOwner: soleOwner,
|
||||
env,
|
||||
log: noopLog,
|
||||
});
|
||||
expect(outcome).toBe("kept");
|
||||
|
||||
const companyHome = resolveManagedGrokHomeDir(env, COMPANY_A);
|
||||
const entries = await readdir(companyHome);
|
||||
expect(entries).toEqual(["auth.json"]);
|
||||
});
|
||||
|
||||
it("redacts the credential bytes on a kept (not-fresher) outcome the same way as a promoted outcome", async () => {
|
||||
const home = await makeInstanceRoot();
|
||||
|
||||
@@ -77,13 +77,6 @@ describe("grok-auth-merge-decision predicate", () => {
|
||||
}
|
||||
}
|
||||
|
||||
it("uses the source when the identity matches and the source expiry is later", async () => {
|
||||
const now = Date.now();
|
||||
const sourceAuth = usableAuthJson({ marker: "src", expiresAt: new Date(now + 2 * 60_000).toISOString() });
|
||||
const destinationAuth = usableAuthJson({ marker: "dst", expiresAt: new Date(now + 60_000).toISOString() });
|
||||
expect(await runDecision({ sourceAuth, destinationAuth })).toBe(USE_SOURCE);
|
||||
});
|
||||
|
||||
it("keeps the destination when the identity key differs", async () => {
|
||||
const now = Date.now();
|
||||
const sourceAuth = usableAuthJson({
|
||||
|
||||
@@ -54,13 +54,7 @@ describe("adapter auth sessions schema", () => {
|
||||
]);
|
||||
// The active index is partial; the where clause is present.
|
||||
expect(active?.config.where).toBeDefined();
|
||||
});
|
||||
|
||||
it("keeps the owner principal non-null and drops the environment from the key", () => {
|
||||
expect(columnIsNotNull(adapterAuthSessions, "started_by_user_id")).toBe(true);
|
||||
const activeColumns = indexColumns(adapterAuthSessions, ACTIVE_INDEX);
|
||||
expect(activeColumns).toContain("started_by_user_id");
|
||||
expect(activeColumns).not.toContain("environment_id");
|
||||
});
|
||||
|
||||
it("adds the public session id, non-null and unique", () => {
|
||||
|
||||
@@ -201,7 +201,6 @@ describeEmbeddedPostgres("applyPendingMigrations", () => {
|
||||
|
||||
it("upgrades renumbered recovery migrations and replays their schema idempotently", async () => {
|
||||
const connectionString = await createTempDatabase();
|
||||
await applyPendingMigrations(connectionString);
|
||||
const recoveryFiles = [
|
||||
"0250_exotic_dakota_north.sql", "0251_narrow_mastermind.sql",
|
||||
"0252_friendly_kate_bishop.sql", "0253_real_firebrand.sql",
|
||||
@@ -271,7 +270,6 @@ describeEmbeddedPostgres("applyPendingMigrations", () => {
|
||||
async () => {
|
||||
const connectionString = await createTempDatabase();
|
||||
|
||||
await applyPendingMigrations(connectionString);
|
||||
|
||||
const sql = postgres(connectionString, { max: 1, onnotice: () => {} });
|
||||
try {
|
||||
@@ -324,7 +322,6 @@ describeEmbeddedPostgres("applyPendingMigrations", () => {
|
||||
async () => {
|
||||
const connectionString = await createTempDatabase();
|
||||
|
||||
await applyPendingMigrations(connectionString);
|
||||
|
||||
const sql = postgres(connectionString, { max: 1, onnotice: () => {} });
|
||||
try {
|
||||
@@ -368,7 +365,6 @@ describeEmbeddedPostgres("applyPendingMigrations", () => {
|
||||
async () => {
|
||||
const connectionString = await createTempDatabase();
|
||||
|
||||
await applyPendingMigrations(connectionString);
|
||||
|
||||
const sql = postgres(connectionString, { max: 1, onnotice: () => {} });
|
||||
try {
|
||||
@@ -398,7 +394,6 @@ describeEmbeddedPostgres("applyPendingMigrations", () => {
|
||||
async () => {
|
||||
const connectionString = await createTempDatabase();
|
||||
|
||||
await applyPendingMigrations(connectionString);
|
||||
|
||||
const sql = postgres(connectionString, { max: 1, onnotice: () => {} });
|
||||
try {
|
||||
@@ -470,7 +465,6 @@ describeEmbeddedPostgres("applyPendingMigrations", () => {
|
||||
async () => {
|
||||
const connectionString = await createTempDatabase();
|
||||
|
||||
await applyPendingMigrations(connectionString);
|
||||
|
||||
const sql = postgres(connectionString, { max: 1, onnotice: () => {} });
|
||||
try {
|
||||
@@ -564,7 +558,6 @@ describeEmbeddedPostgres("applyPendingMigrations", () => {
|
||||
async () => {
|
||||
const connectionString = await createTempDatabase();
|
||||
|
||||
await applyPendingMigrations(connectionString);
|
||||
|
||||
const sql = postgres(connectionString, { max: 1, onnotice: () => {} });
|
||||
try {
|
||||
@@ -630,7 +623,6 @@ describeEmbeddedPostgres("applyPendingMigrations", () => {
|
||||
async () => {
|
||||
const connectionString = await createTempDatabase();
|
||||
|
||||
await applyPendingMigrations(connectionString);
|
||||
|
||||
const sql = postgres(connectionString, { max: 1, onnotice: () => {} });
|
||||
try {
|
||||
@@ -696,7 +688,6 @@ describeEmbeddedPostgres("applyPendingMigrations", () => {
|
||||
async () => {
|
||||
const connectionString = await createTempDatabase();
|
||||
|
||||
await applyPendingMigrations(connectionString);
|
||||
|
||||
const sql = postgres(connectionString, { max: 1, onnotice: () => {} });
|
||||
try {
|
||||
@@ -770,7 +761,6 @@ describeEmbeddedPostgres("applyPendingMigrations", () => {
|
||||
async () => {
|
||||
const connectionString = await createTempDatabase();
|
||||
|
||||
await applyPendingMigrations(connectionString);
|
||||
|
||||
const builtInResourcesHash = await migrationHash(
|
||||
"0140_built_in_managed_resources.sql",
|
||||
@@ -874,7 +864,6 @@ describeEmbeddedPostgres("applyPendingMigrations", () => {
|
||||
async () => {
|
||||
const connectionString = await createTempDatabase();
|
||||
|
||||
await applyPendingMigrations(connectionString);
|
||||
|
||||
const sql = postgres(connectionString, { max: 1, onnotice: () => {} });
|
||||
try {
|
||||
@@ -1007,7 +996,6 @@ describeEmbeddedPostgres("applyPendingMigrations", () => {
|
||||
async () => {
|
||||
const connectionString = await createTempDatabase();
|
||||
|
||||
await applyPendingMigrations(connectionString);
|
||||
|
||||
const repairSweepHash = await migrationHash(
|
||||
"0135_repair_run_responsible_user_updated_at_sweep.sql",
|
||||
@@ -1403,7 +1391,6 @@ describeEmbeddedPostgres("applyPendingMigrations", () => {
|
||||
async () => {
|
||||
const connectionString = await createTempDatabase();
|
||||
|
||||
await applyPendingMigrations(connectionString);
|
||||
|
||||
const sql = postgres(connectionString, { max: 1, onnotice: () => {} });
|
||||
try {
|
||||
@@ -1980,7 +1967,6 @@ describeEmbeddedPostgres("applyPendingMigrations", () => {
|
||||
"replays the idempotent provider trace migration",
|
||||
async () => {
|
||||
const connectionString = await createTempDatabase();
|
||||
await applyPendingMigrations(connectionString);
|
||||
const hash = await migrationHash(
|
||||
"0234_provider_trace_records.sql",
|
||||
);
|
||||
@@ -2008,7 +1994,6 @@ describeEmbeddedPostgres("applyPendingMigrations", () => {
|
||||
"removes retired model profiles from live records and configuration revisions",
|
||||
async () => {
|
||||
const connectionString = await createTempDatabase();
|
||||
await applyPendingMigrations(connectionString);
|
||||
const hash = await migrationHash("0236_remove_cheap_model_profiles.sql");
|
||||
const companyId = "10000000-0000-4000-8000-000000000236";
|
||||
const agentId = "20000000-0000-4000-8000-000000000236";
|
||||
|
||||
@@ -676,11 +676,9 @@ server/src/routes/issues.ts
|
||||
server/src/routes/agents.ts
|
||||
server/src/routes/openapi.ts
|
||||
server/src/__tests__/native-runner-standalone.integration.test.ts (new)
|
||||
server/src/__tests__/heartbeat-native-runner-selection.test.ts (new)
|
||||
server/src/__tests__/heartbeat-native-runner-cancellation.test.ts (new)
|
||||
server/src/__tests__/heartbeat-run-event-sequencing.test.ts (new)
|
||||
server/src/__tests__/native-runner-input-boundary.test.ts (new)
|
||||
server/src/__tests__/native-run-finalizer.test.ts (new)
|
||||
server/src/__tests__/native-status-arbiter-corpus.test.ts (new)
|
||||
server/src/__tests__/native-finalization-recovery.test.ts (new)
|
||||
server/src/__tests__/native-finalization-migration.test.ts (new)
|
||||
@@ -988,13 +986,11 @@ packages/shared/src/validators/native-finalization.ts
|
||||
scripts/check-runner-sdk-spec.mjs
|
||||
server/package.json
|
||||
server/src/__tests__/heartbeat-native-runner-cancellation.test.ts
|
||||
server/src/__tests__/heartbeat-native-runner-selection.test.ts
|
||||
server/src/__tests__/heartbeat-run-event-sequencing.test.ts
|
||||
server/src/__tests__/legacy-finalization-regression.test.ts
|
||||
server/src/__tests__/native-finalization-migration.test.ts
|
||||
server/src/__tests__/native-finalization-recovery.test.ts
|
||||
server/src/__tests__/native-interaction-bridge.test.ts
|
||||
server/src/__tests__/native-run-finalizer.test.ts
|
||||
server/src/__tests__/native-runner-input-boundary.test.ts
|
||||
server/src/__tests__/native-runner-standalone.integration.test.ts
|
||||
server/src/__tests__/native-session-resumption.test.ts
|
||||
@@ -1065,11 +1061,12 @@ Targeted real integration proof:
|
||||
```sh
|
||||
pnpm --filter @paperclipai/server exec vitest run \
|
||||
src/__tests__/native-runner-standalone.integration.test.ts \
|
||||
src/__tests__/heartbeat-native-runner-selection.test.ts \
|
||||
src/services/native-runtime/runtime-mode.test.ts \
|
||||
src/__tests__/heartbeat-native-runner-cancellation.test.ts \
|
||||
src/__tests__/heartbeat-run-event-sequencing.test.ts \
|
||||
src/__tests__/native-runner-input-boundary.test.ts \
|
||||
src/__tests__/native-run-finalizer.test.ts \
|
||||
src/services/native-runtime/paperclip-control-plane-port.test.ts \
|
||||
src/services/native-runtime/evidence-classifier.test.ts \
|
||||
src/__tests__/native-status-arbiter-corpus.test.ts \
|
||||
src/__tests__/native-finalization-recovery.test.ts \
|
||||
src/__tests__/native-finalization-migration.test.ts \
|
||||
|
||||
@@ -46,7 +46,7 @@ const lifecycleRequirements = [
|
||||
["secrets", "secret isolation and network restrictions", "src/live/clean-room-server.test.ts; runner/crates/runner-core/src/durable/runner.rs"],
|
||||
["transcript-accounting", "assistant transcript capture, token usage, and cost inputs", "src/live/live-session.test.ts; src/cli/eval-session.ts"],
|
||||
["state-reconstruction", "fixture and post-run state reconstruction", "src/scenarios/scenario-explorer.test.ts; src/live/live-session.test.ts"],
|
||||
["paperclip-adapter-selection", "paperclip_runner is selectable without changing legacy adapter behavior", "server/src/services/native-runtime/runtime-mode.test.ts; server/src/__tests__/heartbeat-native-runner-selection.test.ts"],
|
||||
["paperclip-adapter-selection", "paperclip_runner is selectable without changing legacy adapter behavior", "server/src/services/native-runtime/runtime-mode.test.ts"],
|
||||
["real-control-plane-binding", "advertised runner tools re-authorize the live company, issue, agent, and run before using real Paperclip services", "server/src/services/native-runtime/paperclip-runner-tool-authority.test.ts; server/src/services/native-runtime/paperclip-runner-real-server.integration.test.ts"],
|
||||
["shared-paperclip-prp-route", "Rust runnerd authenticates to the shared Paperclip server route and completes a real bound semantic tool call", "server/src/realtime/runner-prp-ws.test.ts; server/src/services/native-runtime/paperclip-runner-real-server.integration.test.ts"],
|
||||
["real-control-plane-idempotency", "real service mutations are replay-safe and reject conflicting idempotency-key reuse", "server/src/services/native-runtime/paperclip-runner-tool-authority.test.ts"],
|
||||
|
||||
Loaded 100 of 204 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user