Skip to content

fix(ses): tolerate frozen null arguments/caller pills; preserve yarn install state; declare dep resolutions - #1442

Closed
kriscendobot wants to merge 1 commit into
master-ebc7904from
mirror/endo-3372-ses-frozen-null-pills
Closed

kriscendobot wants to merge 1 commit into
master-ebc7904from
mirror/endo-3372-ses-frozen-null-pills

Conversation

@kriscendobot

@kriscendobot kriscendobot commented Oct 13, 2026 •

Copy link
Copy Markdown
Collaborator

Refs: endojs/endo#3372 (mirror)

Description

This PR bundles three changes:

  1. ses fix (the main change). Chromium's V8 through at least 133, as shipped in the Android System WebView, gives every Web IDL function own, frozen arguments: null and caller: null properties. lockdown() could not delete them and threw, so SES could not initialize there. cauterizeProperty now tolerates exactly that shape with a warning, just as it tolerates an undeletable prototype. Any other value, or a writable pill, still fails lockdown.
  2. Root package.json resolutions for configstore and nconf, which eshost-cli pulls in, declared so hardened-mode installs pass. The resolved versions in yarn.lock do not change.
  3. git clean keeps .yarn/install-state.gz. Without it, yarn clean and pack-all delete Yarn's install state, and every later yarn run then reports the project as not installed. A shared helper holds the arguments, and a test pins the root clean script to it.

Security Considerations

A frozen null is inert: it cannot change and it leaks nothing. Every other shape still fails lockdown.

Scaling Considerations

None.

Documentation Considerations

The ses changeset describes the new tolerance.

Testing Considerations

frozen-null-pill-warnings(-node).test.js plant pills on a replacement Array.isArray. They check that a frozen null pill passes lockdown with a warning, and that a frozen non-null pill and a writable null pill still fail. A scripts test checks the clean arguments in a scratch repo. On the API 36 x86_64 emulator, lockdown completes in the WebView with this change.

Compatibility Considerations

lockdown() now succeeds on more inputs. It still fails on every shape it failed on before, apart from the frozen null pill.

Upgrade Considerations

None.

kriscendobot added a commit to kriscendobot/garden that referenced this pull request Oct 13, 2026
@kriscendobot

kriscendobot commented Oct 13, 2026 •

Copy link
Copy Markdown
Collaborator Author

Mirror of endojs/endo#3376 (head ad7dfe9).

kriscendobot added a commit to kriscendobot/garden that referenced this pull request Oct 13, 2026
@kriskowal

Copy link
Copy Markdown
Member

@kriscendobot Please gauntlet, and particularly make sure to shepherd.

@kriskowal

Copy link
Copy Markdown
Member

@kriscendobot And also, please answer upstream feedback here.

kriscendobot added a commit to kriscendobot/garden that referenced this pull request Oct 13, 2026
@kriscendobot

Copy link
Copy Markdown
Collaborator Author

On it — I've posted a job (endojs-endo-but-for-bots-pr1442-shepherd) and will follow up here when it lands.

model automatic · host endolin-garden-ece02cb4 · garden fad05c57

kriscendobot added a commit to kriscendobot/garden that referenced this pull request Oct 13, 2026
@kriscendobot

Copy link
Copy Markdown
Collaborator Author

On it — I've posted a job (endojs-endo-but-for-bots-pr1442-69bf491a) and will follow up here when it lands.

model automatic · host endolin-garden-ece02cb4 · garden fad05c57

@kriscendobot

kriscendobot commented Oct 13, 2026 •

Copy link
Copy Markdown
Collaborator Author

Answer to the upstream packaging question: the configstore and nconf resolutions are not required by the SES fix. The lockfile already resolves those dependencies outside their requested ranges. Yarn's fork-PR hardened mode rejects those undeclared overrides with YN0078 before tests run. The manifest entries declare the existing overrides; the lockfile edit only rekeys them and changes no installed versions. They can be split, but external PR CI will remain unable to install until the same fix reaches the base branch.

model gpt-5.6-sol · harness codex · provider openai · host endolin-garden-ece02cb4 · garden fad05c57

@kriscendobot

Copy link
Copy Markdown
Collaborator Author

Shepherding complete · CI: 🟢 green · next: gauntlet may continue

Head 4395ad9a6e06d548c0b6e8c721f1230fd3edb708.

  • ebb296608a — preserved Yarn's install state across git clean, fixing the lint and viable-release failures that reported the project was no longer installed.
  • 4395ad9a6e — made the frozen-null-pill assertion type-safe, clearing the API-docs type error exposed after the cleanup fix.
  • Declined items: none.

Verification: CI run 38464246368 is green across all 14 checks. The two macOS jobs were initially cancelled without acquiring runners due to hosted-runner capacity, then passed on the failed-job rerun. Locally, the focused SES tests passed (4 tests), API docs built with 0 errors, lint/prettier passed, the cleanup regression tests passed (3 tests), and yarn pack:all produced all 45 tarballs. The local publish smoke test could not start its disposable Verdaccio server, but the CI viable-release publish smoke test passed.

@kriscendobot kriscendobot left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Panel verdict — round 1: must-fix

Reviewed head 4395ad9a6e06d548c0b6e8c721f1230fd3edb708 against base 356d6e70af (master-356d6e7). 33 seats ran: 4 request-changes (stylist, integrator, changeset-auditor, pruner), 17 comment-only, 12 approve.

Binding pre-pass findings (deterministic):

  • PR-body template pre-pass: NONCONFORMING — template guidance blockquotes and the #XXXX issue placeholder are still in the body; fill or delete them (headings: description; security; scaling; documentation; testing; compatibility; upgrade considerations).
  • PR-body concision probe: 540 words (> 300) — cut to what the reviewer needs.

Must-fix (request-changes seats)

stylist — request-changes

Verdict: request-changes

Findings

  1. must-fix — packages/ses/src/cauterize-property.js (new block, const desc = getOwnPropertyDescriptor(obj, prop)). desc is an abbreviation of descriptor, and it is freshly authored. [rule: roles/jurors/stylist/AGENT.md § Abbreviated identifiers] Rename it to descriptor. Other code in the same file or package may already use desc. That does not exempt a new name.

  2. must-fix — scripts/pack-all.mjs (touched lines) and scripts/pack-all.mjs:run. The run helper's cmd parameter is an abbreviation of command. This PR changes calls to run but not its signature, so the abbreviation was already there and is not a new finding. Comment-only, no action needed.

  3. should-fix — packages/ses/test/error/_prepare-with-frozen-null-pills.js. const pill = shapes[shape] is acceptable. The args in (...args) is a bare abbreviation of arguments, but the full name collides with the very property under test. Leave it, and optionally write restArguments instead. Comment-only.

  4. comment-only — scripts/git-clean-arguments.mjs. The module and the gitCleanArguments export follow the spelled-out convention. The quote helper and argument parameter in the test are fine too. The commandArguments parameter is good.

  5. comment-only — scripts/git-clean-arguments.test.mjs:5. The JSDoc {@link git-clean-arguments.mjs} names the module file, not the exported identifier gitCleanArguments. It is a doc-name mismatch, but a minor one. Consider {@link gitCleanArguments}.

  6. comment-only — the "pill" vocabulary (frozen-null-pills, pillShape, pill) is consistent between the changeset, the tests and the source comment. The source comment says "poison pills", so the shorthand is understandable. pillShape is a global read by globalThis.pillShape. Nothing to change.

No gratuitous renames. No redundant-word concatenations found.
model claude-opus-5-5 · harness claude · provider anthropic

integrator — request-changes

Verdict: request-changes

Findings

  1. must-fix: PR body does not follow the template. [rule: skills/pr-formation § Use the upstream template]
    The pre-pass found template guidance still in the body: every > guidance block, the "Delete guidance…" line, and a #XXXX issue placeholder. Refill the body section for section: Description, Security, Scaling, Documentation, Testing, Compatibility, Upgrade considerations. Delete all guidance and fill or remove the #XXXX line.

  2. must-fix: the PR bundles three unrelated changes, so the merge-commit title can't name what landed. [rule: skills/pr-formation; integrator axes "Merge-commit readability" and "Commit grouping"]

    • The ses lockdown tolerance (the PR's stated purpose) shares the PR with the root package.json resolutions configstore@npm:^1.4.0→5.0.1 and nconf@npm:^0.8.2→0.13.0, and with the git clean / .yarn/install-state.gz preservation (scripts/git-clean-arguments.mjs, scripts/pack-all.mjs).
    • Each is a separate fix, but the title and body will read as the SES change alone.
    • The yarn.lock edit only renames two descriptors; the resolved versions don't change.
    • Either split the unrelated chore and fix into their own PRs, or retitle and describe the PR to cover all three.
    • Separately, the fixup! commit 4395ad9a6e must be autosquashed before merge.
  3. should-fix: the "shared" clean arguments are duplicated. [rule: integrator axis "Convention probe"]

    • scripts/git-clean-arguments.mjs says it is shared by pack-all.mjs and the root clean script.
    • But package.json's clean hardcodes the same flags as a string, so two sources of truth remain.
    • Nothing pins them to match. The new test pins the helper's behavior but not the package.json string.
    • Either assert in the test that the package.json clean script equals the helper's arguments, or have clean invoke a script that imports the helper.
  4. should-fix: stale remnants of the old resolution key. [rule: skills/rename-discipline]

    • yarn.lock now keys the entries as configstore@npm:5.0.1 and nconf@npm:0.13.0.
    • Check that no other manifest still requests configstore ^1.4.0 or nconf ^0.8.2, so the resolutions aren't dead entries.
    • Run grep -rn over the workspace package.json files to confirm.
  5. comment-only: the test fixture is wired to two modes.
    _prepare-with-frozen-null-pills.js picks its shape from globalThis.pillShape or process.argv[2]. That is a reasonable way to serve both the in-process and the child-process tests. The in-process test only covers the frozen-null case, which is fine, because the node tests cover the failing shapes.

  6. comment-only: the changeset is coherent. It is a ses patch, and its description matches the code. No changeset covers the root scripts, which is correct because they are private.

Self-improvement: no new standing rule proposed. The "PR bundles unrelated fixes under one title" check is already covered by the merge-commit readability axis.
model claude-opus-5-5 · harness claude · provider anthropic

changeset-auditor — request-changes

Verdict: request-changes (summary-fix, minor)

Findings

  1. Sentence-per-line violated. .changeset/frozen-null-pills.md puts three sentences on one line: the lockdown() tolerance sentence, the "Chromium's V8 through at least 133…" sentence, and "Any other value, or a writable or configurable pill, still fails lockdown." Put each sentence on its own line. The first sentence is long, so consider splitting it too (for example, state the tolerance, then the "as it already tolerates an undeletable prototype" comparison). [rule: skills/changeset-discipline/SKILL.md § Sentence-per-line]

Checked, no findings

  • Package set. The front-matter lists ses, which is the name in packages/ses/package.json. The only package source touched is packages/ses/src/cauterize-property.js, plus tests under packages/ses/test/error/. The scripts/, root package.json and yarn.lock changes are private workspace tooling, so they correctly need no changeset entry.
  • Bump level. patch fits, because lockdown now succeeds where it used to fail on a narrow input. No new public API is added, and strictness is kept for other values and for writable or configurable pills.
  • Body vs. diff. The body names arguments, caller, frozen null, and the non-writable, non-configurable state. These match the cauterize-property.js change. It does not name any identifier the diff doesn't touch.
  • Process commentary. None. The Chromium/WebView sentence is background rationale, not agent narration.
  • Bundling. There is a single changeset for a single affected package, which is correct.
  • New-package shape. Not applicable; the diff adds no new package.
    model claude-opus-5-5 · harness claude · provider anthropic
pruner — request-changes

Verdict: request-changes


Finding: PR body contains unfilled template boilerplate guidance text that should be removed

The PR body retains template instruction blocks and guidance prompts that should be deleted before merge:

  1. "Most PRs should close a specific Issue..." instruction block (multiple sentences of guidance)
  2. All "> " guidance-text lines under "Description", "Security Considerations", "Scaling Considerations", "Documentation Considerations", "Testing Considerations", "Compatibility Considerations", and "Upgrade Considerations" — each block is a boilerplate prompt prompting the author to fill it in, not substantive content.
  3. The footer ASCII-art comment is decorative boilerplate.

The substantive content (the agent-authored section: "Chromium's V8 through at least 133...", "cauterizeProperty now tolerates...", evidence from the API 36 emulator, and test coverage) is appropriate and should remain.

Recommendation: Remove the guidance-text blocks entirely. If any template section is meant to stay (e.g., "Security Considerations" is genuinely applicable), replace the boilerplate prompt with one sentence of substance or omit it.

Disposition: summary-fix

Rule: [proposed-rule: PR descriptions should not retain unfilled template sections with boilerplate instruction text; if a section applies, populate it with substance; if not, either omit the heading or replace with one sentence]

The code comments in the diff (in cauterize-property.js and new test setup files) document engine-specific quirks and non-obvious invariants appropriately; no padding detected in comments.
model claude-opus-5-5 · harness claude · provider anthropic

Comment-only seats

assessor — comment-only

Verdict: comment-only

The core cauterizeProperty change in packages/ses/src/cauterize-property.js:64-83 is correct and I found no must-fix defects.

  • Control flow: The prototype branch falls through when its tolerance check fails. The new branch is guarded by typeof obj === 'function' and prop being arguments or caller. It is evaluated only in the catch path, after hasOwn is true. When the descriptor is not an inert frozen null, execution reaches error(...) and then throw err, so lockdown still fails.
  • Descriptor check: It requires value === null, writable === false and configurable === false. An accessor descriptor has value undefined, so it is correctly rejected. Reading the descriptor with getOwnPropertyDescriptor from commons.js is safe.
  • Tests: They cover the frozen-null, frozen-zero and writable-null shapes, plus the survival of the pills after lockdown.

Findings

  1. should-fix, scope. The PR bundles three unrelated changes. Besides the SES lockdown fix, it adds a git clean change (package.json clean, scripts/git-clean-arguments.mjs, scripts/pack-all.mjs) and a pair of configstore / nconf resolutions with yarn.lock edits. The changeset covers only ses. The fix is not a correctness problem, but it makes the PR harder to review and bisect, and it means a revert would hit unrelated work. These should be separate PRs, or at least separate and clearly labeled commits. [proposed-rule: one concern per PR; unrelated tooling and lockfile changes ship separately]

  2. should-fix, package.json clean script. The clean string is hand-duplicated from gitCleanArguments. The only thing keeping them in sync is the third test, which asserts string equality. The quoting is fragile: the quote helper in the test must reproduce the exact hand-written string. This is acceptable, but the script should generate the string or invoke the .mjs directly to avoid drift. A deliberate trade-off is also undocumented: -e '!.yarn/install-state.gz' relies on shell quoting of ! in yarn run.

  3. comment-only, packages/ses/test/error/_prepare-with-frozen-null-pills.js:19-20. const { defineProperties } = Object and const { apply } = Reflect are read before the SES shim runs lockdown, which is fine. The globalThis.pillShape fallback to process.argv[2] means a stray argument in some other runner would silently select a shape or throw "unknown pill shape". This is test-only and low risk.

  4. comment-only, yarn.lock / resolutions. The "configstore@npm:^1.4.0": "npm:5.0.1" and "nconf@npm:^0.8.2": "npm:0.13.0" resolutions only re-key lockfile entries that already resolved to 5.0.1 and 0.13.0. That is a no-op in resolved versions. I could not verify the "hardened-mode installs pass" rationale from the diff alone, and the rationale lives only in the commit message, not in the code. [rule: roles/COMMON.md, provenance for non-obvious pins; it should be recorded near the pin or in the changeset]

No performance concerns.
model claude-opus-5-5 · harness claude · provider anthropic

typist — comment-only

Verdict: comment-only (one must-fix under the inline-import() rule, otherwise sound types)

Findings

  1. must-fix: inline import() type in JSDoc. packages/ses/test/error/frozen-null-pill-warnings.test.js:10-14 has @param {import('ava').ExecutionContext} t. The fix is a top-of-file /** @import { ExecutionContext } from 'ava' */ and a bare ExecutionContext in the @param. [rule: roles/jurors/typist/AGENT.md § Inline import() type references in JSDoc tags]

  2. should-fix: untyped global in a type-checked test helper. packages/ses/test/error/_prepare-with-frozen-null-pills.js:15-18 reads globalThis.pillShape.

    • The file has no // @ts-nocheck, unlike the sibling frozen-null-pill-warnings-node.test.js.
    • If packages/ses/tsconfig.json includes test/ (I didn't confirm), pillShape is not declared on typeof globalThis and fails under noImplicitAny. lockdown is probably declared globally already.
    • The fix is // @ts-nocheck, or a cast: /** @type {any} */ (globalThis).pillShape.
    • Please confirm with yarn lint:types in packages/ses. [proposed-rule: test helpers that read ad-hoc globals carry @ts-nocheck or an explicit cast]
  3. comment-only: the new cauterizeProperty branch narrows correctly.

    • typeof obj === 'function' narrows the object parameter.
    • getOwnPropertyDescriptor is exported from commons.js.
    • The desc !== undefined guard covers the PropertyDescriptor | undefined return.
    • The @param types on cauterizeProperty still match its behavior, since the signature is unchanged.
    • The function's JSDoc (lines 7-30) describes only the .prototype tolerance. A sentence on the new frozen-null arguments/caller tolerance would keep the doc accurate. The changeset describes it correctly.
  4. comment-only: scripts/git-clean-arguments.mjs and its test are typed correctly.

    • Object.freeze([...]) gives readonly string[].
    • Spreading it into git(...commandArguments: string[]) and run(...) is fine.
    • The /** @param {string} argument */ annotations are accurate.
    • makeScratchRepo returns a git function with an inferred type, which is fine.
  5. Code-point check: the added text uses ASCII only. The — (em dash) in the pack-all.mjs header comment is in line with the repo's existing style.
    model claude-opus-5-5 · harness claude · provider anthropic

packager — comment-only

Verdict: comment-only

Findings

  1. should-fix (diff hygiene, unrelated scope). Commits ebb296608a (fix(scripts): yarn install-state preservation, scripts/pack-all.mjs, new scripts/git-clean-arguments.{mjs,test.mjs}, the clean script in package.json) and b9d391353e (chore(deps): configstore/nconf resolutions) don't relate to the PR's apparent subject, SES tolerating frozen-null pills (f040b54870). Neither is mentioned in the changeset. They are in separate commits, so they can be reviewed and dropped independently. Still, either state in the PR description why they ride along, or move them to their own PR. [rule: roles/jurors/packager/AGENT.md § Operating norms, "diff carries only what the PR claims"]

  2. should-fix (yarn.lock commit separation). b9d391353e puts the package.json resolutions and the yarn.lock change in one commit. The lock diff is small and only renames two descriptor keys, so the mix is mild. The repo convention is a separate chore: Update yarn.lock commit. [rule: skills/yarn-lock-separate-commit/SKILL.md]

  3. should-fix (leftover fixup commit). 4395ad9a6e is a fixup! commit targeting f040b54870 (it changes one line in frozen-null-pill-warnings.test.js). It should be autosquashed before merge so the history carries no fixup! subject. [rule: roles/jurors/packager/AGENT.md § Operating norms, commit splitting]

  4. comment-only (changeset). .changeset/frozen-null-pills.md is ses: patch. That level fits a relaxed-failure fix with a warning and no API change. The prose is accurate, covers the tolerated case, and says the strict failures remain. The changeset says nothing about the root tooling changes. That's acceptable, since those packages are private, but the PR body should mention them. [rule: skills/changeset-discipline/SKILL.md]

  5. comment-only (package surface). No exports, peer-dependency, or typedoc changes. The new _prepare-with-frozen-null-pills.js and _lockdown-with-frozen-null-pills.js fixtures sit under test/ with underscore prefixes, so nothing internal is exposed publicly.

Self-improvement: none proposed. The fixup!-left-in-history check could become a standing packager rule if it recurs.
model claude-opus-5-5 · harness claude · provider anthropic

curator — comment-only

Verdict: comment-only

Findings

  1. No public-surface change (comment-only). cauterizeProperty in packages/ses/src/cauterize-property.js is an internal helper and is not exported from the ses entry points. The prototype exception beside it follows the same pattern. The new scripts/git-clean-arguments.mjs export is repo-internal tooling and is not in any package's exports. No exports are added, removed, renamed or retyped, so there is no surface delta to inventory.

  2. Bump level matches (comment-only). .changeset/frozen-null-pills.md is ses: patch. The change makes lockdown() tolerate an input shape it used to reject, with a warning, and the failure paths for other shapes stay the same. That is a behavioral fix with no signature change, so patch is correct. [rule: skills/changeset-discipline/SKILL.md]

  3. No sibling-surface duplication (comment-only). I looked for a pre-existing sibling for the new tolerance branch. The prototype tolerance branch in the same function, at packages/ses/src/cauterize-property.js just above the new block, is the intended sibling. The new branch follows it in shape (a warn and then return). It is gated narrowly on function objects whose property is arguments or caller, so it doesn't fuse in other concerns.

  4. The git-clean arguments are shared but still duplicated (comment-only). The clean script in package.json hand-writes the same arguments as gitCleanArguments, and scripts/git-clean-arguments.test.mjs pins the two together. That is acceptable. A note for the maintainer: pack-all.mjs also needs -e /dist in its second clean, and that part is not shared. I didn't find a drift risk beyond what the test already covers.

  5. Unrelated changes bundled in (comment-only). package.json adds two resolutions (configstore, nconf) and yarn.lock changes with them. The clean-script fix is also bundled. None of this touches the ses public surface or its changeset, but it is outside the PR's SES focus. The migrator or releaser seats may want to look at the resolutions. No changeset is needed for private root-level tooling.

No must-fix or should-fix items.

Self-improvement: no standing-rule gap found. The curator brief covered this case (a no-surface-change PR with a correct patch bump).
model claude-opus-5-5 · harness claude · provider anthropic

migrator — comment-only

Verdict: comment-only

The ses change only widens what lockdown() accepts, so it is backward-compatible. I found no must-fix items.

Findings

  1. Bump level is correct (no action). The ses patch changeset in .changeset/frozen-null-pills.md fits.

    • Lockdown now tolerates a frozen null arguments or caller property on a function, with a warning. Every environment that passed lockdown before still passes it.
    • The tolerated shape is narrow: own, non-writable, non-configurable, value exactly null. A pill with any other value, or a writable or configurable one, still hits error(...). The frozen-zero and writable-null tests pin this.
    • No export is renamed and no signature changes, so no peer-dep cascade is needed. Downstream packages such as @endo/lockdown, @endo/init and @endo/compartment-mapper only call lockdown() and see no new throw path. [rule: skills/changeset-discipline/SKILL.md]
  2. One behavior shift for callers who parse lockdown warnings (comment-only). Environments with these pills used to throw. They now succeed and emit new Tolerating undeletable … === null warnings under the existing "Removing unpermitted intrinsics" group. A caller that treats any warning there as fatal, or that matches the exact log text, would notice. The changeset describes the new warning, so it is adequately documented. [rule: skills/changeset-discipline/SKILL.md]

  3. Unrelated changes ride along (comment-only).

    • The clean script change, the new scripts/git-clean-arguments.mjs, and the configstore@npm:^1.4.0 → 5.0.1 and nconf@npm:^0.8.2 → 0.13.0 root resolutions are dev-tooling changes. The yarn.lock edit comes with them.
    • They touch only the private root package, so they need no changeset and do not affect any published package.
    • Forcing configstore and nconf across majors could break their consumers in the workspace. I did not trace those consumers. The PR should confirm that the dev-tool consumers still run, for example by naming the two packages that pull them in. [proposed-rule: a resolution that forces a major-version jump should name the dependent and show it still runs]
  4. A fixup! commit is in the head history (comment-only). 4395ad9a6e fixup! fix(ses): tolerate frozen null … should be autosquashed before merge, so the history stays bisectable and matches the commit conventions. [rule: AGENTS.md § Commit conventions]

Self-improvement: none needed.
les that were kept before. The unit test pins it, including a check that package.json stays in sync with the shared argument list.

Self-improvement: none needed.
model claude-opus-5-5 · harness claude · provider anthropic

warden — comment-only

Verdict: comment-only (no must-fix on the SES boundary)

Findings

  1. Comment-only: the tolerated shape is safe. [rule: roles/jurors/warden/AGENT.md § Primary surface]

    • packages/ses/src/cauterize-property.js:64-83 accepts a leftover own arguments or caller only if all of these hold: typeof obj === 'function', the property name is one of the two, desc.value === null, writable === false, and configurable === false.
    • A frozen null data property carries no authority, so it can't leak a caller frame or be reassigned.
    • An accessor descriptor has value === undefined, so it still fails lockdown.
    • The descriptor is read through the commons.js getOwnPropertyDescriptor binding (captured before lockdown), not a live global.
    • The tolerated property survives lockdown, but harden still freezes the function and the pill stays inert.
  2. Comment-only: no TOCTOU or proxy hazard. The descriptor read happens on intrinsics that the permit walk already visited, after delete failed. A hostile proxy would have to be a pre-lockdown intrinsic, which is outside SES's threat model.

  3. Comment-only: the tests cover the right negatives.

    • The frozen 0 case and the writable null case must still fail.
    • The positive test also asserts the pills survive as null after lockdown.
    • _prepare-with-frozen-null-pills.js mutates Array.isArray before lockdown. The ava test imports it in-process, so it may leak into other tests in the same worker. The Array.isArray wrapper delegates correctly, so this is low risk. Confirm the file's _ prefix keeps it out of the test glob, and consider running it in a fresh process only.
  4. should-fix (scope, not SES): unrelated changes bundled into a ses patch PR.

    • The PR also changes the root clean script, adds scripts/git-clean-arguments.mjs and its test, edits pack-all.mjs, and adds resolutions for configstore@npm:^1.4.0 → 5.0.1 and nconf@npm:^0.8.2 → 0.13.0 in package.json and yarn.lock.
    • These are build-tooling changes with no relation to the lockdown fix, and the changeset doesn't mention them.
    • They are dev-dependency resolutions only. Neither shipped ses code nor the lockdown boundary is affected.
    • Splitting them out would make bisecting easier, and there is a commit-granularity argument for doing so. [proposed-rule: keep SES-boundary patch PRs free of unrelated tooling and resolution churn.]
  5. Comment-only: the new clean regression test is redundant. The "root clean script uses shared args" test only re-derives the quoting of one string. package.json can't import the .mjs module, so this duplication is the only drift guard available.

No unguarded globals, no prototype walks on untrusted input, and no unhardened objects crossing a boundary. This PR adds no Far or exo surface, so the guard-vs-Far concern doesn't apply.

Self-improvement: none.
model claude-opus-5-5 · harness claude · provider anthropic

saboteur — comment-only

Verdict: comment-only

Findings

  1. Mitigated: the tolerated pill shape is narrow and checked on the live descriptor. cauterize-property.js requires typeof obj === 'function', a prop of arguments or caller, and a descriptor with value === null, writable === false and configurable === false. The tests cover frozen 0 and writable null and show both still fail. An accessor descriptor has value === undefined, so it also fails. A Proxy that lies about its descriptor can't happen here, because obj comes from the permit walk over intrinsics. [rule: skills/adversarial-tests/SKILL.md]

  2. Out of scope (breaker overlap): later passes over a surviving own arguments/caller pill. The tolerated property stays on the intrinsic after cauterizeProperty returns. The new tests only prove that lockdown() completes and that Array.isArray still works. They don't show that harden or freeze, or the permit-conformance pass, accepts an own arguments/caller on a function whose permit says it has none. This was not run against a real V8 WebView, so the claim "lockdown now works there" is unverified. The test imitates the pills on one planted function (Array.isArray) in Node. [rule: roles/jurors/saboteur/AGENT.md § Verified-claim evidence discipline] The changeset states a WebView outcome as fact, so I suggest hedging it or citing an actual run.

  3. Should-fix: unrelated yarn resolutions ride along. package.json pins configstore@npm:^1.4.0 to npm:5.0.1 and nconf@npm:^0.8.2 to npm:0.13.0, and yarn.lock is rewritten to match. The configstore pin is a four-major jump for consumers that declared ^1.4.0. Neither pin is mentioned in the changeset or tied to the SES fix. A consumer that depends on the old API would break at runtime, and no test exercises that path. Split these into their own PR, or justify them. [proposed-rule: one concern per PR. Dependency-resolution pins need their own rationale and changeset.]

  4. Comment-only: the git clean change is a third unrelated concern. The change to package.json's clean script, scripts/git-clean-arguments.mjs and pack-all.mjs is also unrelated to the SES change.

    • Mitigated: the test drives real git clean in a scratch repo and has a negative control, so it is load-bearing.
    • Risk: scripts.clean is duplicated in package.json and gitCleanArguments, and the third test syncs them by reconstructing shell quoting. A new argument containing a space or special character would need the quote helper updated as well.
    • Positive check: -fX without -d leaves ignored directories alone, so the comment that -e node_modules only restates .gitignore is accurate.
  5. Nit: the test helper's default shape. _prepare-with-frozen-null-pills.js falls back to process.argv[2] and then 'frozen-null'. If the in-process ava test runs with extra argv, process.argv[2] could pick up an ava argument. An unknown value throws unknown pill shape, which would give a confusing failure. This is low risk, since the in-process test is not given a shape argument by ava workers. Explicit selection would be tighter.

No new try/catch and no JSON parsing were added, so the tight-try and located-error rules do not apply.
model claude-opus-5-5 · harness claude · provider anthropic

breaker — comment-only

Verdict: comment-only

Nothing here falsifies a claimed invariant. The findings are should-fix or comment-only.

Invariants and attacks

  • Claim: the changeset and the code comment say tolerance covers only a frozen null (non-writable, non-configurable), and any other pill still fails lockdown.
  • Attack 1: an accessor pill (get/set), a non-null value, a writable pill, or a configurable pill. Each falls through to error(...) and rethrows. The tests cover 0 and writable null, so this is mitigated.
  • Attack 2: make the tolerance leak a live capability. The accepted shape is non-writable, non-configurable and null, so it holds no capability and cannot be mutated after lockdown. desc.value === null on an accessor is undefined, so accessors are rejected. Mitigated.
  • Attack 3: use the descriptor check to pass the wrong object. The hasOwn guard and the typeof obj === 'function' guard both precede the check. The descriptor is read after delete threw, so there is no check-then-use gap. A Proxy with a lying getOwnPropertyDescriptor trap would have to be an intrinsic that survived earlier steps, which is out of scope.
  • Attack 4: known === true on a permit of false. The tolerance warns regardless of known. That is harmless and arguably right.

Findings

  1. Should-fix, scope creep. package.json adds resolutions for configstore@npm:^1.4.0 → 5.0.1 and nconf@npm:^0.8.2 → 0.13.0, with a yarn.lock key rewrite. The git clean and install-state.gz change is also unrelated to the SES fix. The PR bundles three independent changes under a SES-only patch changeset, and the dependency resolutions are the riskiest of them. Split them out, or at least name them in the PR description. [proposed-rule: one PR per concern; dependency-graph resolutions never ride in a runtime-fix PR]
  2. Comment-only, test brittleness. The third test in scripts/git-clean-arguments.test.mjs reconstructs the package.json clean string with a hand-written quote helper. That pins the exact string and couples it to a shell-quoting detail. The single-quoted '!.yarn/install-state.gz' also fails under Windows cmd for the root clean script. This is minor, since pack-all.mjs avoids the problem by passing argv directly.
  3. Comment-only, sibling family. The prototype branch and the new arguments/caller branch are the only two pill tolerances. Other undeletable own properties that V8 might add to Web IDL functions, such as length or name, are not tolerated. That is consistent with the stated narrow scope, so I expect no new findings. git grep found no other cauterizeProperty call site that needs the same change.
  4. Comment-only. The warn fires per function, so on an affected WebView lockdown logs two warnings for every Web IDL function. That is noisy but not incorrect.

Self-improvement: none to record.
model claude-opus-5-5 · harness claude · provider anthropic

purist — comment-only

Verdict: comment-only

Findings

  1. comment-only: the cauterizeProperty tolerance is narrow and consistent. packages/ses/src/cauterize-property.js:64-83 tolerates only the exact shape null, non-writable, non-configurable, and only for arguments/caller on functions. A frozen null is inert, so it opens no side channel, and the surrounding prototype tolerance is the closest relative. I did not read how permits.js handles arguments/caller on Function.prototype. Function.prototype itself is a function, so it is also covered. [rule: roles/jurors/purist/AGENT.md § Family-consistency]

  2. comment-only: the remaining family members are not tolerated. A non-writable, non-configurable undefined pill would still fail. The frozen null case does match the observed V8 behaviour. The changeset says "Any other value … still fails", so this is documented. No action needed.

  3. should-fix: URL-relative path math in scripts/git-clean-arguments.test.mjs. fileURLToPath(new URL('..', import.meta.url)) is already the URL form, so that line is fine. The test then builds paths with join(repoRoot, ...). Those inputs are native path strings (repoRoot, mkdtemp results), so I would not flag them. [rule: roles/jurors/purist/AGENT.md § URL-relative path math]

  4. comment-only: package.json clean duplicates the args list. package.json hard-codes the same arguments as gitCleanArguments. The test pins them together, so the duplication is guarded. A single source of truth would be nicer, for example "clean": "node scripts/git-clean.mjs". That is a minimum-viable-abstraction taste point; the test's quote-reconstruction is somewhat brittle. [rule: roles/jurors/purist/AGENT.md § Minimum viable abstraction]

  5. should-fix: scope mixing. The PR bundles three unrelated changes: the SES pill tolerance, the git clean install-state fix, and the configstore/nconf resolutions with yarn.lock. Only the first is covered by the changeset. Splitting them would keep each change bisectable and reviewable on its own. [proposed-rule: one concern per PR, or at least per clearly separable commit set]

  6. comment-only: the test helper plants the pills on Array.isArray. _prepare-with-frozen-null-pills.js reads globalThis.pillShape and process.argv[2] as a test-only switch. That is acceptable for a test fixture. The fixture's defineProperties(Array, { isArray: { value } }) keeps the existing property attributes, which is good.

No passability or side-channel concerns.

Self-improvement: none.
model claude-opus-5-5 · harness claude · provider anthropic

spec-keeper — comment-only

Verdict: comment-only

Findings

  1. comment-only — packages/ses/src/cauterize-property.js (the new arguments/caller branch) and .changeset/frozen-null-pills.md give no spec citation. The tolerated shape is a frozen null data property named arguments or caller, which is not what the spec prescribes. ECMA-262 §10.2.4 AddRestrictedFunctionProperties defines %Function.prototype%.arguments and .caller as accessors that throw %ThrowTypeError%. No ECMA-262 clause gives ordinary or built-in functions an own arguments or caller. These are non-standard V8 and Web IDL leakage.

    • The code comment should say the tolerance is deliberately off-spec and engine-specific. It should also point at a V8 or Chromium issue, or at the Web IDL behavior it claims, so a maintainer can retire it later.
    • "V8 through at least 133" is the only evidence offered. A link would let someone confirm when it stops applying.
    • [rule: skills/pr-review-thread-replies — none apply; proposed-rule: engine-variance tolerances in cauterize-property must cite the spec clause they deviate from and an engine bug link]
  2. comment-only — Primordial preservation is fine. The change uses getOwnPropertyDescriptor from commons.js, which is the captured primordial, and it checks typeof obj === 'function' before reading the descriptor. No .call or method-on-foreign-value issues.

  3. should-fix (minor) — packages/ses/test/error/_prepare-with-frozen-null-pills.js and the tests are engine-agnostic. They synthesize the pills with defineProperties, and no real V8 or WebView instance is exercised, so they do not confirm the claimed behavior. That is acceptable for a unit test. The spec-keeper concern is the changeset's claim that Chromium behaves this way, which nothing in the PR verifies. A link to the Chromium bug, or a recorded eshost dump, would back it.

  4. comment-only — The PR bundles unrelated changes: git clean install-state preservation, scripts/git-clean-arguments.mjs, and the configstore/nconf resolutions with matching yarn.lock edits. These are outside my spec/engine-variance scope and I did not evaluate them. Splitting them into separate PRs would make bisecting and review easier.

  5. comment-only (hygiene) — The test helper reads process.argv[2] and globalThis.pillShape for the same purpose. That works, but the dual channel is slightly surprising. A one-line comment is enough.

Self-improvement: a proposed rule for spec-keeper is to require that engine-quirk tolerances in SES cite both the spec clause being deviated from and an upstream engine bug link.
model claude-opus-5-5 · harness claude · provider anthropic

wire-watcher — comment-only

Verdict: comment-only

Findings

  1. comment-only: the tolerated shape is the inert one, so trust is not widened. packages/ses/src/cauterize-property.js:64-83 only reaches the new branch after delete has already failed. It requires typeof obj === 'function', prop equal to arguments or caller, and a data descriptor with value === null, writable === false and configurable === false.

    • A property in that state cannot be rewritten, redefined or deleted, and null carries no capability, so tolerating it cannot expose an authority.
    • An accessor descriptor has value === undefined and falls through to error. A missing descriptor (desc === undefined) also falls through.
    • The check reads the descriptor directly, not through a getter. There is no in-band marker or parser-divergence concern here. [rule: roles/jurors/wire-watcher/AGENT.md § Operating norms, in-band-marker trust-bypass]
  2. comment-only: two bypass cases are not tested.

    • _prepare-with-frozen-null-pills.js covers frozen-null, frozen-zero and writable-null. The near-miss cases are not covered: a non-writable but configurable pill, which delete would just remove, and an accessor pill that returns null. Both fall to error by construction.
    • An accessor test would pin that the desc.value === null check cannot be satisfied by a getter. This is the "syntactically valid but wrong" test the brief asks for. [proposed-rule: for tolerance carve-outs in cauterize-property, add a test for each descriptor-shape near-miss, including the accessor.]
  3. comment-only: the warning is the only record of the tolerance. The pill survives lockdown and Array.isArray.arguments === null stays observable. The test asserts this, which is good.

    • The tolerance is not scoped to intrinsics.* paths, only to function objects. That is fine, because cauterizeProperty only visits permitted-intrinsic subpaths.
    • Anyone auditing post-lockdown state should know that arguments and caller can exist as frozen nulls.
  4. comment-only: the dependency-resolution edit (package.json, yarn.lock) is unrelated to the wire. The configstore@npm:^1.4.0 and nconf@npm:^0.8.2 resolutions force a major-version jump for transitive dependencies. The lockfile already resolved to 5.0.1 and 0.13.0, so the change only renames the descriptors. The risk is that other consumers could now be forced onto these versions. Bundling it with the SES fix makes review and bisect harder, but it is not a protocol concern.

  5. comment-only: git-clean-arguments negation. The -e '!.yarn/install-state.gz' exclude is pinned by tests against a scratch repository, and the package.json string is cross-checked against the shared array. I found no trust-boundary issue.

No must-fix or should-fix items.

Self-improvement: when a PR relaxes a failure path, check that the tolerated shape is closed under mutation (non-writable and non-configurable) as well as inert in value.
model claude-opus-5-5 · harness claude · provider anthropic

engine-realist — comment-only

Verdict: comment-only

Engine reality checks out: the getOwnPropertyDescriptor import exists in commons.js, and the capture is module-load time.

Findings

  1. Comment-only: strict-mode delete assumption.

    • packages/ses/src/cauterize-property.js:64-83: the tolerance branch only runs when delete obj[prop] throws. SES modules are strict, so V8 and XS throw on a non-configurable delete. That is the path the Chromium WebView pills take, so the assumption holds.
    • Under a sloppy-mode embedder bundle, delete returns false silently and the pill is never examined. That is harmless but untested.
  2. Should-fix: no XS coverage for the new behavior.

    • The new tests are two ava files, test/error/frozen-null-pill-warnings.test.js and its -node child-process variant. The package's test:xs runs only _lockdown-safe.js and a generated file, so neither new test runs on XS.
    • On XS, Function objects may expose arguments or caller differently. The permits path for those properties is the same code, so the risk is low.
    • Say explicitly that the XS arm is out of scope. Alternatively, add the frozen-null case to the XS generated test. [rule: skills/coverage-driven-testing/SKILL.md § Platform-conditional arms]
  3. Comment-only: the test is synthetic.

    • test/error/_prepare-with-frozen-null-pills.js:24 fakes the pills on Array.isArray with defineProperties. This does not prove that real V8 WebView functions hit the cauterizeProperty path, for example if the permit walk never visits Web IDL functions.
    • The planted property is on a function the permits table visits, so the code path is real.
  4. Comment-only: the shared git clean arguments are only partly pinned.

    • The -e '!.yarn/install-state.gz' exclude works only with the -fX plus -e combination. scripts/git-clean-arguments.test.mjs pins that behavior against the real .gitignore, which is good.
    • The root clean script string is compared against the shared module's quoting, so it has to track quote() exactly. This is brittle but covered by a test.
  5. Should-fix (scope): unrelated changes bundled into an SES lockdown PR.

    • The PR also adds the configstore and nconf resolutions and the matching yarn.lock key renames, plus the git clean rework.
    • They are not engine-related and belong in separate commits or PRs. They also widen the review surface for a ses patch release.

No must-fix. Nothing here crashes or leaks on V8 or XS, and the runtime change is narrowly gated: it takes only a frozen null, and the other shapes still fail lockdown.

Self-improvement: none.
model claude-opus-5-5 · harness claude · provider anthropic

scribe — comment-only

Verdict: comment-only

Findings

No maintainer note-this ask is open on this PR. I read the PR's top-level comments, review comments and reviews. The only maintainer directives are:

  • #issuecomment-6154549264: "gauntlet, and particularly make sure to shepherd".
  • #issuecomment-6154566755: "answer upstream feedback here".

Neither asks for a standing-orders or CLAUDE.md note. The PR's diff has no standing-orders edit, and none is needed.

Completion-summary closure (met):

  • The upstream-feedback ask is closed. #issuecomment-6154973742 answers the upstream packaging question about the configstore and nconf resolutions.
  • The shepherd ask is closed. #issuecomment-6155133689 is a top-level "Shepherding complete" comment naming head 4395ad9a6e, listing ebb296608a, and reporting CI green.
  • Both responding pushes (ebb296608a and the 4395ad9a6e fixup) are covered by that summary. The summary body I read was truncated, so I did not check whether it also covers declined items and verification detail.

Observations (non-blocking):

  1. Open question: the 4395ad9a6e fixup is still unsquashed. It is a fixup! commit on top of f040b54870. I can't tell from the PR history whether a squash is planned before the mirror lands. If one is expected, that is a process follow-up for the gauntlet/weaver, not a missing note. I'm raising it as a question, not citing a rule.
  2. Possible gap: the scripts/git-clean-arguments.mjs rationale isn't recorded. Preserving Yarn install state across git clean fixes a real CI failure. It is a behavioural rule that future builders could break by changing the clean arguments. The PR comment and the changeset capture the "why". No maintainer asked for a standing note, so this is optional. [proposed-rule: when a script change encodes a non-obvious CI-failure workaround, leave a short code comment at the site pointing to the failure mode.]

No summary-fix or must-fix-loop needed.
model claude-opus-5-5 · harness claude · provider anthropic

gateway — comment-only

Verdict: comment-only

Findings

  1. Root package.json resolutions: justified, no action. configstore@npm:^1.4.0 → 5.0.1 and nconf@npm:^0.8.2 → 0.13.0 (package.json:94-95). The commit b9d391353e says what changed (declare the pins that yarn.lock already carried), the scope (repo-wide, via eshost-cli's transitive deps), and why. Without the declaration, hardened mode (YN0078) fails every fork PR's install step. The commit says it was tested with YARN_ENABLE_HARDENED_MODE=1 yarn install --immutable. resolutions can only be set at the root, so a per-package override isn't possible. This is a tightening: it makes the manifest match the lockfile and doesn't change the resolved versions. yarn.lock changes only the two entry keys, and no versions change. [rule: gateway brief § Operating norms, scope-justification check]

  2. Root package.json clean script: no stated rationale in the PR's own commits (summary-fix). package.json:52 adds -e '!.yarn/install-state.gz' to git clean. This narrows what the root yarn clean deletes. It also changes the clean behavior of scripts/pack-all.mjs, which now shares gitCleanArguments. Commit ebb296608a says "preserve Yarn install state", and the code comment points to git-clean-arguments.mjs for the rationale. But the commit body never says why a repo-wide change is needed or what breaks without it. For example, it doesn't say whether a full re-install is triggered, or which workflow loses the state. Please add one or two sentences to the commit message or PR body naming the failure this prevents, for example that yarn clean or pack-all discards the install state, which then forces or breaks the next yarn or yarn run. The scope itself looks right, because both clean and pack-all already share one root-level command, so a per-package override isn't an alternative. This script is a relaxation of a destructive step: less is deleted, but ignored artifacts that sit under the exception path may survive. Check that the negated pattern !.yarn/install-state.gz actually works, which is what the scratch-repo test scripts/git-clean-arguments.test.mjs appears to do. [proposed-rule: a change to a root clean or pack script must state in the commit body which artifact it now preserves or removes and which workflow motivated it]

  3. Unrelated changes bundled in one PR (summary-fix, low). The diff mixes a ses runtime fix (cauterize-property.js), a hardened-mode lockfile/manifest fix, and a clean-script change. The three root-config changes are explained separately in their own commits, so this is fine for the gateway. But the PR body should state the scope of each root-level touch in one place. [proposed-rule: a PR touching root config for several independent reasons lists each touch with its scope in the PR body]

  4. .changeset/frozen-null-pills.md: not a gate change. It covers only the ses fix. Nothing for the gateway to flag.

No .github/workflows/*, tsconfig*, eslint configs, or other gate files are touched.
model claude-opus-5-5 · harness claude · provider anthropic

corner-prober — comment-only

Verdict: comment-only

Findings

Boundary enumeration for the pill predicate (typeof obj === 'function', prop ∈ {arguments, caller}, frozen null). Covered: frozen-null, frozen-zero, writable-null. The cases below are missing.

  1. Non-writable but configurable null (missing, summary-fix). configurable: true makes the delete succeed, so the tolerance branch is never reached. The configurable === false clause is therefore unreachable in practice, and no test shows which path a configurable pill takes. The tests all hard-code configurable: false. Add a case or drop the redundant clause. [rule: skills/adversarial-tests/SKILL.md § Boundary sweep]

  2. Accessor pill (missing, summary-fix). V8's pill on strict functions is a getter/setter accessor (%ThrowTypeError%). For an accessor descriptor, desc.value is undefined and desc.writable is undefined, so the predicate fails. That is the right outcome, since lockdown should still fail. But the tests never exercise an accessor-shaped arguments, so a future loosening of the predicate (for example desc.value == null) would go unpinned. Add a get/set shape to shapes. [rule: skills/adversarial-tests/SKILL.md § Boundary sweep]

  3. undefined value (missing, summary-fix). A frozen undefined fails === null. This is the nearest neighbour of the accepted value, and an == null slip would accept it. Add a frozen-undefined shape expecting failure. [proposed-rule: for strict-equality tolerance predicates, test the loose-equality neighbour (undefined for null, 0 and '' for false).]

  4. Mixed pill pair (missing, summary-fix). Only arguments and caller together are tested with the same shape. Cases with arguments frozen-null and caller frozen-zero (or only one pill present) are not covered. Check that the tolerated property does not mask the failing one, and that only one failure is reported.

  5. Non-function owners (missing, summary-fix). typeof obj === 'function' excludes objects, but no test puts a frozen-null arguments on a non-function intrinsic (for example Array.prototype) and expects failure. Also uncovered: a callable class or a bound function, whose typeof is 'function' as well.

  6. Other path shapes (missing, minor). The tests only cover the intrinsics.Array.isArray.* subPath. A prototype method such as Array.prototype.map is unexercised, and so is a Symbol-keyed prop (prop is a symbol, so the === comparison is fine, but the warn string is untested).

  7. git-clean-arguments test coupling (minor, comment-only).

    • The test that compares package.json's clean script against the quoted argument list will break on any shell-quoting change.
    • It is also sensitive to git clean semantics across git versions (negated -e with a trailing-/ directory). The .yarn/stray case is covered, but not an install-state.gz nested at a deeper path.
  8. resolutions change (note). The new configstore@npm:^1.4.0 → 5.0.1 and nconf@npm:^0.8.2 → 0.13.0 resolutions are a major-version jump from the declared ranges, with no evidence that consumers still work. This is outside corner-probing scope, but it is worth a reviewer's glance.

The implementation itself is sound at the boundary: the predicate is strict, and unknown shapes fall through to error.

Self-improvement: propose adding "accessor vs data descriptor" and "strict-equality neighbour (undefined for null)" to the corner-prober's descriptor-domain checklist.
model claude-opus-5-5 · harness claude · provider anthropic

fast-checker — comment-only

Verdict: comment-only

Findings

  1. The pill-shape predicate is a three-way conjunction, tested at 3 fixed points. cauterizeProperty tolerates only {value: null, writable: false, configurable: false} on function arguments/caller. frozen-null-pill-warnings-node.test.js covers one passing shape and two failing shapes. Each failing shape flips one field, so writable: true is covered but configurable: true is not.

    • A configurable: true pill would normally be deletable, so it may be unreachable. The desc.configurable === false clause is then dead and the claim "a writable or configurable pill still fails" is untested.
    • Suggested property: fc.assert(fc.property(fc.record({ value: fc.constantFrom(null, 0, undefined, '', {}), writable: fc.boolean() }), pill => outcomeOf(pill) === (pill.value === null && !pill.writable ? 'tolerated' : 'fails')), { numRuns: 20 }).
    • Each run spawns a child process (the lockdown test cannot be repeated in-process), so keep numRuns small, or collapse the arbitrary to fc.constantFrom over the full shape cross-product (value × writable). Enumerating the 2×2×N shapes in a table is equally honest and cheaper than fast-check here.
    • Disposition: summary-fix. [proposed-rule: when a predicate gates on N independent descriptor fields, test the full cross-product of those fields, by fc.record or an explicit table, not one flip per field]
  2. git-clean-arguments.test.mjs hand-lists one scratch tree. The preserve/delete contract is "for any set of ignored paths, only .yarn/install-state.gz and node_modules/** survive". Today it is checked on one fixed layout of five files.

    • A property would be fc.assert(fc.asyncProperty(fc.uniqueArray(fc.constantFrom('.yarn/stray', 'yarn-error.log', 'coverage/x', 'dist/a.js', '.yarn/cache/z')), ...)), asserting that the install state and node_modules always survive and every generated stray file is removed.
    • Given the per-run git init cost, numRuns: 10 is enough. The benefit is modest, since the contract is really about one negated pattern.
    • Disposition: follow-up, low priority. [proposed-rule: none; the existing example test is adequate for a single-pattern exclusion]
  3. fast-check is not used in the touched code. Neither packages/ses tests nor scripts/ appear to need it for the core change.

    • The cauterizeProperty change has a small, enumerable input space, so a table of shapes is appropriate and a new devDependency is not warranted.
    • No introduce fast-check finding is raised. [rule: none]
  4. Nit on the logging test. compareLogs in frozen-null-pill-warnings.test.js is a hand-rolled ordered-subsequence matcher.

    • It has no unit test of its own, so a bug in it (for example, never failing) would silently weaken the assertion.
    • Its correctness is cross-checked by the -node test, which asserts the same lines independently, so the risk is low. A property would be: for any list and any subsequence of it, compareLogs passes.
    • Disposition: follow-up, optional.

No must-fix-loop items. The PR claims no universally-quantified contract that the examples fail to verify.

Self-improvement: add a skills/adversarial-tests § Property-based testing note that predicates gating on several descriptor fields need cross-product coverage, and that process-spawning tests should prefer an enumerated table over fc.assert.
model claude-opus-5-5 · harness claude · provider anthropic

coverage-auditor — comment-only

Verdict: comment-only

Findings:

  • coverage of new lines could not be verified: no c8 coverage report at '/home/kris/garden/scratch/project-wt-endojs--062218c929b7-41c67140/coverage/coverage-final.json' (run c8 with --all --reporter=json, or set GARDEN_COVERAGE_JSON); cannot verify new-line coverage — NOT assuming covered. Produce a c8 report (c8 --all --reporter=json) so new-line coverage can be checked, or confirm this package is intentionally outside coverage. This is surfaced, NOT treated as covered. [rule: skills/coverage-driven-testing/SKILL.md]
    model claude-opus-5-5 · harness claude · provider anthropic

Approving seats

archivist, prover, locksmith, duality-auditor, benchmarker, surfacer, releaser, transplanter, orthographer, thesaurus, procurer, reexport-auditor — approve, no findings requiring action (full text in the durable panel-run record).

model claude-opus-5-5 · harness claude · provider anthropic · host endolin-garden-ece02cb4 · garden fad05c57

@kriscendobot kriscendobot changed the title fix(ses): tolerate frozen null arguments/caller pills on API functions fix(ses): tolerate frozen null arguments/caller pills; preserve yarn install state; declare dep resolutions Oct 14, 2026

@kriscendobot kriscendobot left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Panel verdict — round 2: must-fix

Reviewed head 26b4d946cf60f7f5c829c625728c874ad9325af7 against base 356d6e70af (master-356d6e7). 33 seats ran: 4 request-changes (stylist, packager, archivist, integrator), 20 comment-only, 9 approve.

Binding pre-pass findings (deterministic):

  • PR-body concision probe: the description touches 5 distinct file paths — cut to what the reviewer needs (skills/pr-formation, skills/gricean-maxims).

Must-fix:

  • Squash the literal fixup! commit 4395ad9a6e into f040b54870 before merge (packager #1).

Should-fix (bucketed from request-changes seats):

  • Fold 26b4d946cf ("address panel review") into f040b54870 so the history reads as logical pieces (packager #2, integrator #2).
  • Scope: the git clean/install-state.gz script fix and the configstore/nconf resolutions ride along with the SES fix — name all three in the title/description (or split), and say which package pulls in the resolutions (integrator #1/#4, packager #3).
  • Pin package.json's clean script against gitCleanArguments in a test so the duplicated argument list cannot drift; confirm the existing "root clean script uses the shared arguments" test covers it (integrator #3, packager #5).
  • _prepare-with-frozen-null-pills.js: fix the garbled opening comment ("that permit removal will visit") (archivist #1); rename shapes/pill to descriptor names and use one name for shape/pillShape (stylist #4).

Request-changes seats

stylist — request-changes

Verdict: request-changes

Findings

  1. must-fix: abbreviated parameter in a new test helper.

    • scripts/git-clean-arguments.test.mjs, in makeScratchRepo, spells out commandArguments and directory. That part is fine.
    • scripts/pack-all.mjs and its run = (cmd, argv, options) helper use cmd and argv. They predate this PR, so they are not findings.
    • The new test file has no further freshly authored bare abbreviations, so this item is withdrawn: none.
  2. must-fix: stdio redefined as a module constant, shadowing nothing but opaque. Withdrawn. It matches the spawn option name, which is a platform name.

  3. should-fix: file name and variable use "pill", an unexplained metaphor.

    • packages/ses/test/error/_prepare-with-frozen-null-pills.js:1 and frozen-null-pill-warnings*.test.js use "pill". The source calls them "poison pills", but the bare "pill" is jargon.
    • It matches the usage in the cauterize-property.js comment, which defines it. This is acceptable, so comment-only.
  4. should-fix: shapes and shape hold a value property descriptor, not a shape.

    • _prepare-with-frozen-null-pills.js:19-27 names pill and shapes for what are partial property descriptors (value, writable).
    • pillDescriptors[pillShape] would say what they are.
    • Also, globalThis.pillShape is named pillShape while the local is shape. Use one name.
  5. comment-only: the argument name isArrayWithPills is clear. originalIsArray is also fine.

  6. comment-only: gitCleanArguments is a good, spelled-out name. It matches the file name. The -e node_modules redundancy is documented.

  7. comment-only: package.json resolutions.

    • The new "configstore@npm:^1.4.0": "npm:5.0.1" and "nconf@npm:^0.8.2": "npm:0.13.0" entries are unrelated to the PR's stated claim, the SES frozen null pill fix. The same is true of the clean script change.
    • These look like carried-over commits from the mirror branch.
    • Flag for the packager to confirm. They are not naming issues.

Summary: There are no must-fix naming problems. The only actionable naming change is item 4, the shape/pillShape and pill/shapes inconsistency in the test prepare file.

[proposed-rule: test fixtures that hold property descriptors should be named for descriptors, not for the scenario label.]

Self-improvement: I first drafted two must-fix items and then withdrew them. Next time I should check whether an identifier is a platform name or predates the PR before listing it.
model claude-opus-5-5 · harness claude · provider anthropic

packager — request-changes

Verdict: request-changes

Findings

  1. must-fix: unsquashed fixup! commit. 4395ad9a6e is a literal fixup! fix(ses): tolerate frozen null arguments/caller pills on API functions that touches frozen-null-pill-warnings.test.js by one line. It needs an autosquash into f040b54870 before merge. [rule: skills/pr-creation-flow/SKILL.md]

  2. should-fix: a second "address panel review" commit stays on top. 26b4d946cf edits the changeset, cauterize-property.js and the test, all of which f040b54870 introduced. The history would be cleaner with it folded into f040b54870, because the review round-trip carries no value for the reader. Leave it if the project keeps review-round commits. [rule: skills/changeset-discipline/SKILL.md]

  3. should-fix: unrelated changes ride in a PR whose stated scope is the SES fix. Two commits are not SES work:

    • b9d391353e declares configstore@npm:^1.4.0 and nconf@npm:^0.8.2 resolutions. It is separate and correctly carries its own yarn.lock change, which satisfies [rule: skills/yarn-lock-separate-commit/SKILL.md].
    • ebb296608a makes pack-all and yarn clean preserve .yarn/install-state.gz.

    Both are root and tooling changes, and neither is mentioned in the changeset. That is acceptable because they are non-published, and they are well split into their own commits. However, the PR title and description should call out that they ride along, or they should move to a separate PR. [rule: skills/pr-creation-flow/SKILL.md]

  4. comment-only: the changeset is accurate and the bump level is right. .changeset/frozen-null-pills.md has ses: patch. This is a tolerance fix with no API change, and the prose matches the cauterize-property.js behavior (frozen null accepted with a warning; any other value, or a writable or configurable pill, still fails). The root package.json and scripts/ changes are correctly left out of the changeset. [rule: skills/changeset-discipline/SKILL.md]

  5. comment-only: git clean is now spelled in three places. package.json clean hardcodes -e '!.yarn/install-state.gz', scripts/git-clean-arguments.mjs holds it for pack-all, and the pack-all.mjs header comment repeats it. The three can drift. The git-clean-arguments.test.mjs test might not cover the package.json copy. Consider having a test assert that package.json's clean script matches gitCleanArguments. [proposed-rule: when a command line is duplicated between a package.json script and a shared .mjs constant, assert parity in a test.]

  6. comment-only: the resolutions pin a lockfile key to an exact version. The lock entries changed from configstore@npm:^1.4.0 to configstore@npm:5.0.1, and from nconf@npm:^0.8.2 to nconf@npm:0.13.0. This is a consistent result of resolutions and the lock diff is minimal. No peer-range or exports issues appear in this diff.

Self-improvement: no new standing rule needed beyond the proposed parity check.
model claude-opus-5-5 · harness claude · provider anthropic

archivist — request-changes

Verdict: request-changes

Findings:

  1. Comment phrasing clarity — _prepare-with-frozen-null-pills.js:3–4 [should-fix]
    The opening comment reads "Plant own, undeletable arguments and caller properties on an intrinsic function that permit removal will visit." The phrase "that permit removal will visit" is grammatically awkward and obscures the intent. The sentence should read "that the removal process will visit" or "that the removal will visit" to clarify that this function is a target for the lockdown removal machinery. This is part of a test setup comment read by maintainers; clearer phrasing helps.

Summary of verified findings:

  • Technical accuracy: All claims about the frozen-null pill tolerance (its engine origin, the exact property shape, the warning behavior) match the code implementation and test expectations.
  • Cross-references: The GitHub issue link in compareLogs JSDoc and the _prepare-with-frozen-null-pills.js comment both resolve to valid URLs.
  • Test assertions: The expected log messages in frozen-null-pill-warnings.test.js match the warn() calls in cauterize-property.js.
  • Documentation scope: The shared rationale for git clean exclusions is correctly documented in git-clean-arguments.mjs and cited from pack-all.mjs.

Self-improvement: This review applied the cross-verification rule by checking that the test assertions match the actual warn() message format, and by confirming that the changeset claims about engine behavior align with the implementation and test scenarios. The single finding is a comment-clarity issue in shared test setup code.
model claude-opus-5-5 · harness claude · provider anthropic

integrator — request-changes

Verdict: request-changes

The PR body was not retrievable (the gh call timed out), so I could not check it against the template. The template pre-pass binds that check regardless.

Findings

  1. should-fix — scope bundling and merge-commit readability. The PR mixes three unrelated concerns:

    • a ses lockdown tolerance change (packages/ses/src/cauterize-property.js);
    • a repo-wide git clean / .yarn/install-state.gz script fix (package.json, scripts/pack-all.mjs, scripts/git-clean-arguments.mjs);
    • root resolutions for configstore and nconf, plus the matching yarn.lock rewrite.

    A title naming the SES fix will mislead a git log reader about the other two. Either split them into separate PRs or make the title and description name all three. The description must follow the template headings and carry no stale scope. [rule: pr-formation]

  2. should-fix — commit grouping. 4395ad9a6e fixup! … and 26b4d946cf fix(ses): address panel review… are review-round commits. They should be squashed into f040b54870 before merge so the history reads as logical pieces. The scripts fix and the resolutions commit are already separate, which is good. [rule: roles/jurors/integrator Commit grouping]

  3. should-fix — convention probe and forward-compose. The -e '!.yarn/install-state.gz' argument list now lives in three places:

    • the gitCleanArguments module,
    • the package.json clean script string, which cannot import the module,
    • prose comments in pack-all.mjs.

    The sharing comment in scripts/git-clean-arguments.mjs claims the root clean script shares the arguments, but package.json duplicates the literal. The new test pins the module, so check that it also asserts the package.json string matches. If it does not, the two can drift silently. Could clean call a tiny script that uses the shared list? [rule: proposed-rule: a shared constant that a package.json script cannot import needs a drift-pin test]

  4. comment-only — changeset coverage. .changeset/frozen-null-pills.md covers ses correctly. The scripts and resolutions changes are repo-internal and need no changeset. The resolutions bump to configstore 5.0.1 and nconf 0.13.0 is a dependency-graph change with no rationale in the diff. The commit message says "so hardened-mode installs pass"; the PR body should say which package pulls them in, so the next reader does not revert it.

  5. comment-only — acceptance evidence. The new tests cover the frozen-null shape in the ses pill code. The claim about Chromium's V8 through at least 133 in the Android System WebView rests on prose in the changeset and a source comment, with no test of an actual engine. That is acceptable for a tolerance change, but state it in the Testing Considerations section.

No rename sweep, diagram, or cycle concerns apply. No related design PR is declared.

Self-improvement: none.
model claude-opus-5-5 · harness claude · provider anthropic

Other seats

  • assessor — comment-only
  • typist — comment-only
  • prover — comment-only
  • curator — comment-only
  • migrator — comment-only
  • locksmith — comment-only
  • warden — comment-only
  • saboteur — comment-only
  • breaker — comment-only
  • purist — comment-only
  • spec-keeper — comment-only
  • wire-watcher — comment-only
  • engine-realist — comment-only
  • surfacer — comment-only
  • scribe — comment-only
  • gateway — comment-only
  • corner-prober — comment-only
  • fast-checker — comment-only
  • releaser — comment-only
  • coverage-auditor — comment-only
  • duality-auditor — approve
  • benchmarker — approve
  • changeset-auditor — approve
  • pruner — approve
  • transplanter — approve
  • orthographer — approve
  • thesaurus — approve
  • procurer — approve
  • reexport-auditor — approve

(Full comment-only/approve seat text omitted to fit GitHub's review size limit.)

model claude-opus-5-5 · harness claude · provider anthropic · host endolin-garden-ece02cb4 · garden fad05c57

@kriscendobot
kriscendobot force-pushed the mirror/endo-3372-ses-frozen-null-pills branch from 26b4d94 to eec274b Compare October 14, 2026 01:35
@kriskowal

Copy link
Copy Markdown
Member

Answer to the upstream packaging question: the configstore and nconf resolutions are not required by the SES fix. The lockfile already resolves those dependencies outside their requested ranges. Yarn's fork-PR hardened mode rejects those undeclared overrides with YN0078 before tests run. The manifest entries declare the existing overrides; the lockfile edit only rekeys them and changes no installed versions. They can be split, but external PR CI will remain unable to install until the same fix reaches the base branch.

model gpt-5.6-sol · harness codex · provider openai · host endolin-garden-ece02cb4 · garden fad05c57

Please remove the overrides and shepherd through CI to verify that the changes are superfluous.

@kriskowal

Copy link
Copy Markdown
Member

@kriscendobot rsvp

Answer to the upstream packaging question: the configstore and nconf resolutions are not required by the SES fix. The lockfile already resolves those dependencies outside their requested ranges. Yarn's fork-PR hardened mode rejects those undeclared overrides with YN0078 before tests run. The manifest entries declare the existing overrides; the lockfile edit only rekeys them and changes no installed versions. They can be split, but external PR CI will remain unable to install until the same fix reaches the base branch.
model gpt-5.6-sol · harness codex · provider openai · host endolin-garden-ece02cb4 · garden fad05c57

Please remove the overrides and shepherd through CI to verify that the changes are superfluous.

kriscendobot added a commit to kriscendobot/garden that referenced this pull request Oct 14, 2026
@kriscendobot

Copy link
Copy Markdown
Collaborator Author

On it — I've posted a job (endojs-endo-but-for-bots-pr1442-7f8fa973) and will follow up here when it lands.

model automatic · host endolin-garden-ece02cb4 · garden 82fc050e

@kriscendobot
kriscendobot force-pushed the mirror/endo-3372-ses-frozen-null-pills branch 2 times, most recently from d75cf0a to eec274b Compare October 14, 2026 18:15
@kriscendobot

kriscendobot commented Oct 14, 2026 •

Copy link
Copy Markdown
Collaborator Author

Feedback loop complete · CI: green · next: maintainer review

Head eec274bad823147d61a04facc964f8e198eaac49.

  • I removed the configstore and nconf overrides and lockfile rekeys, producing trial head d75cf0acfb8e06e4da3feb97b8b051324eb3fb03.
  • The resulting CI run failed 12 of 12 install-dependent jobs in Yarn hardened mode with YN0078: Invalid resolution configstore@npm:^1.4.0 -> npm:5.0.1. This directly shows the declarations are required for fork-PR CI, rather than superfluous.
  • I therefore restored the declarations by returning the branch to its exact prior head, eec274bad823147d61a04facc964f8e198eaac49.

Verification: the fresh restoration CI run is green. Its first test-xs attempt hit an operational SSL download failure; rerunning the failed job passed. Locally on the removal trial, yarn exec ava scripts/git-clean-arguments.test.mjs packages/ses/test/error/frozen-null-pill-warnings-node.test.js packages/ses/test/error/frozen-null-pill-warnings.test.js passed all 7 tests.

No requested item was silently declined: permanent removal was reversed because the requested CI experiment falsified its premise.

@kriskowal

Copy link
Copy Markdown
Member

@kriscendobot Please rebase on upstream master, which recently merged the changes to fix CI underneath yours.

kriscendobot added a commit to kriscendobot/garden that referenced this pull request Oct 14, 2026
@kriscendobot

Copy link
Copy Markdown
Collaborator Author

On it — I've posted a job (endojs-endo-but-for-bots-pr1442-rebase) and will follow up here when it lands.

model automatic · host endolin-garden-ece02cb4 · garden 460f0598

Chromium's V8 through at least 133 (the Android System WebView on the
API 36 emulator image) gives every Web IDL function own, non-writable,
non-configurable `arguments: null` and `caller: null` properties.
lockdown() tried to delete them during permit removal, could not, and
threw SES_UNCAUGHT_EXCEPTION, so SES could not initialize there at all.
Desktop Chromium 148 has no such properties.

cauterizeProperty now tolerates exactly that shape with a warning
("Tolerating undeletable <path> === null"), as it already tolerates an
undeletable `prototype` that can be set to undefined. A frozen null is
inert: it cannot be changed and leaks nothing. Any other value, or a
writable pill, still fails lockdown. (A configurable pill never reaches
this path: it is simply deleted.)

Evidence: on the API 36 x86_64 emulator, lockdown() in the WebView
completes with this change and an Endo app built on it starts and talks
CapTP to a local daemon.

Tests: frozen-null-pill-warnings(-node).test.js plant such pills on a
replacement Array.isArray and check that lockdown succeeds and warns for
frozen null, and still fails for a frozen non-null value and for a
writable null.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@kriscendobot
kriscendobot force-pushed the mirror/endo-3372-ses-frozen-null-pills branch from eec274b to 5091b25 Compare October 14, 2026 21:46
@kriscendobot
kriscendobot changed the base branch from master-356d6e7 to master-ebc7904 October 14, 2026 21:46
@kriscendobot

Copy link
Copy Markdown
Collaborator Author

Rebase complete · CI: 🟡 pending on the new head · next: await the refreshed checks

Head 5091b254cc7830201df228438104617e27f41b19 is rebased onto upstream master at ebc7904d87b130922a6ead072075420d507843e4; the PR now targets the frozen base master-ebc7904.

Rebase details
  • Retained the SES frozen-null-pill change as the PR's sole commit.
  • Dropped the two CI-support commits while replaying because their resolutions and install-state fixes landed independently on upstream master in 41dbe56c24 and 2200e37e4e.
  • The resulting PR delta is limited to the six SES implementation, test, and changeset files.
  • No requested work was declined.
Local verification
  • YARN_ENABLE_HARDENED_MODE=1 yarn install --immutable --mode=skip-build passed (with existing peer-dependency warnings).
  • The two focused AVA test files passed: 4 tests.
  • yarn workspace ses lint passed with 0 errors and 6 existing warnings.
  • git diff --check origin/master-ebc7904..HEAD passed.

@kriscendobot

Copy link
Copy Markdown
Collaborator Author

Gauntlet terminal — halted · rounds run: 3 · head 5091b254cc7830201df228438104617e27f41b19 · CI: red · next: maintainer action required; halt reason: stage 'endojs-endo-but-for-bots-pr1442-gauntlet-panel-3' (panel) failed 3 times; its stage retry budget is exhausted (max_stage_retries=2). Last failure: panel stage reported panel-error (seat/decider error or interruption — a sensor failure, not a review verdict)

Unaddressed must-fix summary

Unaddressed must-fix: 20 · verdict: moving target · rounds spent: 3 · cost so far: $7.31
Trend: r1 n/a; r2 n/a; r3 raised 20
Classes: 0 persistent, 20 new in last round, 0 addressed-then-reintroduced

[new, since r3] archivist: (packages/ses/src/cauterize-property.js:7) should-fix: packages/ses/src/cauterize-property.js:7-26. The JSDoc summary of cauterizeProperty enumerates th...
[new, since r3] archivist: (packages/ses/src/cauterize-property.js:68) comment-only: packages/ses/src/cauterize-property.js:68-70 and .changeset/frozen-null-pills.md:6-7. Both stat...
[new, since r3] archivist: (.changeset/frozen-null-pills.md:5) comment-only: .changeset/frozen-null-pills.md:5-6. The claim "This matches how it already tolerates an undeleta...
[new, since r3] breaker: should-fix: the "a frozen null is inert" invariant is false on V8 for sloppy-mode functions. The new comment at...
[new, since r3] breaker: Attack: a vetted shim, or a polyfill written in sloppy mode, replaces an intrinsic before lockdown(). My repro:...
[new, since r3] breaker: Before this PR: delete throws and lockdown fails closed.
[new, since r3] breaker: With this PR: lockdown succeeds with a warning. After lockdown, Array.isArray.arguments returns the live argume...
[new, since r3] breaker: Result: the PR silently widens what lockdown accepts, beyond the Web IDL builtins it targets.
[new, since r3] breaker: Fix: narrow the shape, for example by requiring that the function never had an own prototype (Web IDL operation...
[new, since r3] breaker: comment-only: the descriptor check holds up against Proxy-based lying. If a function intrinsic is a Proxy, its g...
[new, since r3] breaker: (permits-intrinsics.js:275) comment-only: no siblings were missed. Both paths into cauterizeProperty (permits-intrinsics.js:275 and intr...
[new, since r3] breaker: comment-only: the negative tests are sound but incomplete. frozen-zero and writable-null pin the value and wr...
… and 8 more

model automatic · host endolin-garden-ece02cb4 · garden 460f0598

kriskowal pushed a commit to kriscendobot/garden that referenced this pull request Oct 15, 2026
@kriscendobot

Copy link
Copy Markdown
Collaborator Author

The upstream pull request endojs/endo#3376 was merged.

Closing this mirror to follow. This is an automated action by the
garden mirror-closer (deterministic; no LLM in the loop).

model automatic · host endolin-garden-ece02cb4 · garden abed1bbf

@kriscendobot

Copy link
Copy Markdown
Collaborator Author

🧾 Garden completion receipt — #1442 (closed, not merged)

Completed 2026-10-29T04:03:08Z. 11 engagement(s) across 13 base(s). Basis: calibrated = capped proxy-wallclock × reputation/rate-card.md (true cost); notional = usage-ledger list price (~8.7× high on a flat subscription).

base role harness model tokens (billable) notional $ calibrated $
endojs-endo-but-for-bots-pr1442-69bf491a-retro prosecutor claude claude-opus-5-5 55500 0.61 —
endojs-endo-but-for-bots-pr1442-69bf491a-retro ∑ 55500 0.61 0.01
endojs-endo-but-for-bots-pr1442-69bf491a ∑ 0 0.00 (ceil 0.72)
endojs-endo-but-for-bots-pr1442-7f8fa973-retro prosecutor claude claude-opus-5-5 65165 0.66 —
endojs-endo-but-for-bots-pr1442-7f8fa973-retro ∑ 65165 0.66 0.00
endojs-endo-but-for-bots-pr1442-7f8fa973 ∑ 0 0.00 (ceil 3.93)
endojs-endo-but-for-bots-pr1442-gauntlet-clean gardener claude claude-opus-5-5 38742 0.36 —
endojs-endo-but-for-bots-pr1442-gauntlet-clean ∑ 38742 0.36 0.01
endojs-endo-but-for-bots-pr1442-gauntlet-fix-1 gardener claude claude-opus-5-5 64816 0.77 —
endojs-endo-but-for-bots-pr1442-gauntlet-fix-1 ∑ 64816 0.77 0.04
endojs-endo-but-for-bots-pr1442-gauntlet-fix-2 gardener claude claude-opus-5-5 72318 0.85 —
endojs-endo-but-for-bots-pr1442-gauntlet-fix-2 ∑ 72318 0.85 0.06
endojs-endo-but-for-bots-pr1442-gauntlet-panel-1 gardener claude claude-opus-5-5 88039 2.02 —
endojs-endo-but-for-bots-pr1442-gauntlet-panel-1 ∑ 88039 2.02 0.01
endojs-endo-but-for-bots-pr1442-gauntlet-panel-2 gardener claude claude-opus-5-5 72542 0.82 —
endojs-endo-but-for-bots-pr1442-gauntlet-panel-2 ∑ 72542 0.82 0.01
endojs-endo-but-for-bots-pr1442-gauntlet-panel-3 gardener claude claude-opus-5-5 89375 1.15 —
endojs-endo-but-for-bots-pr1442-gauntlet-panel-3 gardener claude — 57901 0.71 —
endojs-endo-but-for-bots-pr1442-gauntlet-panel-3 gardener claude — 83883 0.99 —
endojs-endo-but-for-bots-pr1442-gauntlet-panel-3 ∑ 231159 2.85 0.14
endojs-endo-but-for-bots-pr1442-gauntlet-viability gardener claude — 40490 0.38 —
endojs-endo-but-for-bots-pr1442-gauntlet-viability ∑ 40490 0.38 0.01
endojs-endo-but-for-bots-pr1442-rebase ∑ 0 0.00 (ceil 6.09)
endojs-endo-but-for-bots-pr1442-shepherd ∑ 0 0.00 (ceil 9.98)
PR total 728771 9.32 0.29

Maintainer review (heuristic): ~188 min ≈ $470.00 — 6 review sitting(s), 18 human comment(s) (84519 chars). That is ≈ 1616× the machine calibrated cost ($0.29).
Total measured cost: $470.29 (machine calibrated $0.29 + MRE $470.00).

Closed-without-merge outcome: unresolved. No evidence-backed attribution has been recorded; do not treat this as either rolled-forward cost or productive learning.

Ceiling (unmeasured openai/unknown arms, a modelling bound not money): $20.72.

Machine review context: 1 panel round(s), 0 fix iteration(s).

Receipt generated deterministically from the journal usage + reputation ledgers and the PR's human review threads. MRE constants a=8 b=1.5 r=750 H=150 (journal-tunable). Archived at receipts/endojs-endo-but-for-bots/2026/10/pr1442.md.

model automatic · host endolin-garden-ece02cb4 · garden abed1bbf

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants