Skip to content

Stateful handler verification matrix and gaps in fixtures suggest; composition-fit discovery fixes (#1136, #1137) - #1142

Merged
jimhoyd merged 5 commits into
mainfrom
claude/issues-1136-1137
Oct 4, 2026
Merged

jimhoyd merged 5 commits into
mainfrom
claude/issues-1136-1137

Conversation

@jimhoyd

@jimhoyd jimhoyd commented Oct 4, 2026

Copy link
Copy Markdown
Collaborator

Problem and change

#1136: make stateful custom-handler verification gaps actionable

  • What fixtures can express today. No fixture syntax was added, and schemas/requests.schema.json is unchanged.

    Invariant Expressible as a fixture?
    Capacity exhaustion Yes
    Persistence across restart Yes
    Parent/derived credential revocation Yes
    Concurrent mutation / idempotency Partly: sequential replay only
    Permission change while an operation waits No
    Delayed cleanup failure No
    Owned-process termination No
  • Reference scenarios. examples/stateful-verification/ is a synthetic "channel" handler:

    • 39 fixture cases; it audits ready.
    • tests/in-flight.test.mjs is a plain node:test for the scenarios fixtures can't express.
    • Six switchable defects; test/stateful-verification.test.ts asserts exactly which checks each one fails.
    • Four of the six fail no fixture at all.
  • Guidance. docs/READINESS.md has a new "Stateful handler verification" section: the matrix, "untested is not passed", and the boundary between fixtures and ordinary tests. AI-AUTHORING and TOOLING point to it.

  • Tooling. urlcode fixtures suggest, MCP suggest_fixtures and the SDK add verificationGaps when a route qualifies:

    • A route qualifies from YAML alone: it has function or middleware, no extension, and a write method or stream: true.
    • status is always untested. It never claims coverage, reads no handler source and runs no project code; a test asserts this.
    • The key is absent otherwise, so existing output is unchanged.

#1137: composition discovery against a real application

The assessment result is on the issue. These changes are each tied to an observed discovery miss:

  • plan-feature. The mcp authoring surfaces gain planner goal words, so plan-feature now names mcp for a remote-MCP goal; before, it returned nothing. The durable-collection note states the store's scope.
  • auth and mcp docs. The surfaces and READMEs now state where each contract stops:
    • the session cookie is the only credential;
    • there is an owner-database option;
    • a schema-adding plugin can't use the bundled database file (with a clearer refusal message);
    • a protected mcp mount refuses headless callers;
    • handlers get no caller identity.
  • docs search. It now matches catalog add-ons on their authoring contract, so oauth, bearer token and postgres name the add-on.
  • TOOLING. It now states that review reads only a route's entry module.
  • Executable composition. test/account-composition.test.ts has four tests with negative authorization cases, plus one test each in feature-plan and review.

Gaps reproduced and filed, not fixed here: #1139, #1140, #1141.

Verification

  • npm run verify exits 0 on this exact tree.

    • Core: 1439 pass.
    • Workspaces: auth 33, mcp 47, store 239.
    • Add-ons and proofs: addons 9, proof 12, authjs 13, native 7, ecosystem 13.
    • 0 failures anywhere.
  • npm run test:package exits 0: "46 packaged example commands ran from consumer copies; Packed installation and starter/cookbook checks passed".

  • Core package budget, from the merged measurement:

    Old budget New budget Measured
    Packed 1098 KiB 1111 KiB 1133642 bytes
    Unpacked 4300 KiB 4348 KiB 4444006 bytes
    Entries 570 576 571

Limitations

Closes #1136
Closes #1137

🤖 Generated with Claude Code

jimhoyd and others added 4 commits October 3, 2026 19:52
… and let the planner find mcp

Running the bounded authoring tools against a real composed application
(#1137) showed four places where the answer existed only in prose, or not at
all. Each edit is tied to one observed miss.

- plan-feature named nothing for an MCP goal: the mcp extension's authoring
  surfaces carried no goal words. `servers` and `mount` now do.
- The mcp mount said "add auth: true" without saying what that admits. With
  the bundled auth extension a request without the site's own Origin is
  refused 403, there is no OAuth or bearer authorization, and a handler is
  not told who called. The surface description, README, llms.txt and
  TOOLING say so.
- The auth surfaces now say what the mount leaves out (admin console, API
  keys, OAuth/OIDC), that its database may be the owner's own, and that the
  session cookie is the only credential the gate admits.
- A Better Auth plugin that adds columns refused to activate on the bundled
  SQLite file with advice that cannot help (`urlcode-auth migrate` does not
  read host.mjs). The refusal and the README now name the owner database.
- docs search matched a catalog add-on on its name and description only, so
  `oauth` or `postgres` named no add-on in a site that installs none. It now
  also reads the authoring contract.
- TOOLING described review as scanning a "source graph". It reads only the
  module each route names; an imported module is not scanned.
- The planner's durable-collection outline states the bundled store's scope
  (flat scalar records, one SQLite database, one serving process).

test/account-composition.test.ts is the executable composition: sign-up,
sign-in, sign-out revocation, an admin-plugin suspension refused to
non-administrators, the headless and bearer refusals on an auth: true MCP
mount, the handler context keys and the plugin-schema refusal.

No runtime behavior changes apart from the refusal message and the wider
catalog match.

Refs #1137.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rios and untested gaps (#1136)

Routes that run project code and can hold state have guarantees the YAML does
not state. This makes those gaps actionable without inferring them.

- fixtures suggest / MCP suggest_fixtures: when a function or middleware route
  with no extension accepts a write method or streams, the result carries
  verificationGaps: seven fixed rows, status "untested", saying which a steps
  fixture can check and which need an ordinary test. YAML only: no handler
  source, fixture or test result is read, nothing is imported, and no row is
  derived from a route name or description. Absent when no route qualifies.
- examples/stateful-verification: one synthetic trusted handler with every row
  as a check. Fixtures cover revocation at event and byte capacity, derived
  credentials, restart and idempotent replay; tests/in-flight.test.mjs (plain
  node:test against startServer) covers a read pending at revocation,
  concurrent publishes, failed cleanup and owned processes. Six deliberate
  defects each fail exactly the checks written for them.
- docs: the matrix and the fixture-versus-ordinary-test boundary in READINESS,
  the authoring rule in AI-AUTHORING, the output contract in TOOLING.

No fixture syntax is added. The package size budget in scripts/package-audit.ts
is exceeded by this change and is left for the coordinator to re-measure.

Refs #1136

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Measured on the merged branch (Node 26): 1133642 packed, 4444006 unpacked,
571 entries. Budgets: 1111 KiB packed, 4348 KiB unpacked, 576 entries.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… so the orphan check holds on Windows

CI (verify windows-latest, 24, 3) failed "defect orphan-process fails exactly the
checks written for it": with the defect on, no check failed. Windows ends a Node
process's non-detached children with it (libuv's kill-on-close job object), so
the tool process the defect leaves behind was already gone and the check could
not see an orphan. The job now starts its tool detached (windowsHide), as tool
runners commonly do, so the orphan exists on every platform unless the handler
ends it. Refs #1136.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jimhoyd
jimhoyd merged commit d9f2270 into main Oct 4, 2026
27 checks passed
@jimhoyd
jimhoyd deleted the claude/issues-1136-1137 branch October 4, 2026 01:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant