Files
PaperClipAI/packages/paperclip-runner/spec/capability/catalog-reconciliation.md
Dotta 560e7e48b5 feat(runner): add SDK and developer tooling (#12608)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The runner package already provides the production protocol and
execution spine.
> - Contributors still need stable SDK surfaces, deterministic test
tools, and local inspection tools.
> - Those surfaces share generated contracts and must change as one
package boundary.
> - This pull request adds the package-local SDK, labs, examples, and
drift checks.
> - The benefit is a reviewable developer platform that does not change
application execution selection.

## Linked Issues or Issue Description

**Subsystem affected**

`packages/paperclip-runner` — runner SDK, conformance tools, and
developer tooling.

**Problem or motivation**

The production runner spine is present, but package consumers cannot
build deterministic integrations, inspect sessions, or verify
provider-neutral behavior through supported surfaces.

**Proposed solution**

Add browser, React, standalone, live-session, scenario, conformance, and
evaluation surfaces. Add generated contract inventories and
package-local verification scripts. Keep production application routing
unchanged.

**Alternatives considered**

We considered splitting each generated catalog, SDK surface, and demo
into separate pull requests. Those changes share exports, fixtures, and
drift gates. Splitting them would create intermediate package states
that do not build.

**Roadmap alignment**

No overlapping item appears in `ROADMAP.md`. This work extends the
runner package that is already on `master`.

## What Changed

- Add browser, React, standalone, live-session, and issue-thread SDK
surfaces.
- Add deterministic mock control-plane, scenario, conformance, replay,
and evaluation tools.
- Add bounded Codex, OpenCode, and ACPX development transports and
fixtures.
- Keep deferred managed-provider execution fail-closed. Persisted
compatibility data remains readable.
- Add generated capability inventories with their source files and drift
checks.
- Add examples, package documentation, browser checks, and
clean-consumer checks.
- Preserve the reviewed protocol bounds, replay compatibility aliases,
process environment isolation, and semantic redaction limits.
- Update the ACPX package patch that the existing workspace patch
registry already tracks.
- Do not change `pnpm-lock.yaml`, repository workflows, server runtime
selection, or the application UI.

## Verification

GitHub Actions is the verification authority for this pull request. The
repository CI, package TypeScript and Rust checks, package tests,
generated-output drift checks, browser checks, security scans, and
Greptile review must pass on the exact head.

Local test suites were not run because this series uses parallel GitHub
Actions for verification.

## Risks

This is a large greenfield package change. The main risks are public
export drift, generated-output drift, and optional React consumer
compatibility. Package boundary checks, clean-consumer checks, and
browser tests cover those risks. Production adapter selection and server
execution are outside this pull request.

## Stack

1. **This PR:** runner SDK and developer tooling.
2. [Codex production server
integration](https://github.com/paperclipai/paperclip/pull/12616).
3. [Provider-neutral task-thread
UI](https://github.com/paperclipai/paperclip/pull/12617).

## Model Used

OpenAI Codex, GPT-5, high-reasoning mode, with tool use and code
execution.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have described the issue in-PR following the feature request
template
- [x] I have not referenced internal/instance-local Paperclip issues or
links
- [x] My branch name describes the change and contains no internal
Paperclip ticket id
- [ ] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge
2026-08-31 21:33:11 -05:00

9.4 KiB
Raw Permalink Blame History

Semantic Catalog Reconciliation

Document status: Canonical reconciliation ledger (TASK-17025 gate + TASK-17039 collapse)
Date: 2026-08-11
Source of truth: src/catalog/canonical-operations.ts (CAPABILITY_CANONICAL_OPERATIONS) — the single hand-authored 41-operation list. Both catalog modules derive their operation set, placement, required claims, and task-mode policy from it.
Drift authority: src/catalog/reconciliation.ts (machine-readable ledger), drift-checked by src/catalog/reconciliation.test.ts and src/catalog/catalog-docs.test.ts.
Parent plan: Runner foundation review plan (TASK-17016), deliverable D and execution step 1.

Purpose

The runner carried two independently hand-maintained semantic catalogs. TASK-17025 established one machine-readable authority over both and recorded every divergence. TASK-17039 performed the physical collapse: the authoritative operation list, placement, required claims, and task-mode policy now live once in src/catalog/canonical-operations.ts, and both catalog modules derive from it — neither declares an independent operation list or an independent claim/mode policy any longer. Each catalog supplies only its per-surface presentation (title, description, input/output schema, and the scenario-only mock mapping and redaction rules), and a bidirectional parity check fails the build if either catalog's presentation set drifts from the canonical surface.

The two catalogs

Catalog Module Count Descriptor Consumers
Scenario / eval src/tools/ 37 (14 always + 23 optional) Rich: placement (disposition), sideEffectClass, idempotency, redaction, mockCommandMapping src/scenarios/*, src/conformance/*; package-root default export
Live runtime src/semantic-tools/ 28 (13 always + 15 optional) Live: exposure, allowedModes, disabledByDefault, provider input/output schemas; runtime dispatcher + policy + redaction src/live/* (live Codex), src/issue-thread/*, generated semantic-tool-contracts.json; package-root acceptedCapabilitySemanticTools

Reconciled op-set relationship (pinned by the drift test):

  • 24 shared operation ids.
  • 13 scenario-only: administer_company, export_company, inspect_operation_result, list_cases, list_company_skills, list_goals, list_projects, list_routines, list_secret_metadata, manage_routine, read_secret_value, sync_company_skills, upsert_case.
  • 4 live-only: get_agent, get_approval, get_approval_context, schedule_wake.
  • Union = 41 operations.

Canonical authority decision

  • Single source of truth: src/catalog/canonical-operations.ts hand-authors the 41-op union exactly once (CAPABILITY_CANONICAL_OPERATIONS), each entry naming surfaces, placement, optional group, claims, task modes, roles, side-effect class, idempotency, disabled-by-default, real-binding status, PRP evidence, and legacy aliases. Both catalog modules import it and project it: src/tools/ renders the rich scenario descriptor and src/semantic-tools/ renders the live provider descriptor.
  • Drift ledger: src/catalog/reconciliation.ts enriches the canonical list with the scenario mock mapping and redaction flag (CAPABILITY_CANONICAL_CATALOG), and capabilityCatalogReconciliation() recomputes the op-set summary and any remaining metadata divergence between the two catalogs' actual descriptors.
  • Neither src/tools/ nor src/semantic-tools/ is canonical; both are projections of canonical-operations.ts.

Real-binding status (before real Paperclip service binding)

No operation is bound to a real Paperclip service yet; the deterministic mock is the only backend (real-service binding is deliverable G). Each operation's current executability is classified as:

  • live_codex (27): executed by the live dispatcher against the mock and exposed to live Codex — the 24 shared ops (minus the test-only escape hatch) plus the 4 live-only ops.
  • scenario_mock (13): defined only in the scenario/eval catalog and driven through the scenario runtime / mock extensions; no live dispatcher binding.
  • test_only (1): generic_api_request — the escape hatch, which by rule cannot count as product capability coverage.

Divergence ledger (after the TASK-17039 collapse)

requiredClaims and task modes are single-sourced from canonical-operations.ts, so the two catalogs cannot diverge on them; the drift test asserts both divergence sets are now empty. The reconciliation ledger recomputes divergences from the two catalogs' actual descriptors:

  • Claims (0): unified. generic_api_request carries a single claim, test:generic_api_request, on both surfaces.
  • Task modes (0): unified to one canonical policy — the live runtime exposure policy unioned with skill_test. Reads stay open in every mode; work-writes (report_progress, write_document, request_human_input, register_deliverable) allow standard/planning/skill_test; lifecycle and state writes (finish_task, block_task, request_review, create_task, set_dependencies, request/decide/comment approvals, control_workspace_service) allow standard/skill_test. The skill_test mode makes every operation the eval harness must drive drivable, while the live runtime keeps its intended per-mode exposure.
  • Input-schema shape (reviewed intentional projection): one input contract is projected two ways by design — the live provider descriptor threads idempotencyKey in-band with provider length/pattern bounds for the model, while the observable scenario runtime threads idempotency out-of-band. This is a single reviewed projection recorded in the ledger, not two independently authored schemas.

Effect on live provider schemas (QA gate)

  • The generated live contract golden generated/capability/semantic-tool-contracts.json is byte-identical after the collapse: it serializes name, description, input/output schema, exposure, and required claims — none of which changed on the live surface (allowedModes is not serialized).
  • The live runtime allowedModes gained skill_test for the nine previously standard-only operations (finish_task, block_task, request_review, create_task, set_dependencies, request_approval, decide_approval, control_workspace_service, schedule_wake). This is a behavioral change to eval-harness exposure only; real live tasks never run in skill_test mode.

Legacy MCP aliases

Legacy MCP aliases are indexed in spec/capability/mcp-tool-map.yaml (inventoryRole: legacy_alias_index, generated from packages/mcp-server). Each alias row carries a foldedInto disposition linking it to the native eval/ operation that now covers its behavior; the reconciliation drift test asserts every row has one. The authority additionally records the direct native operation for the well-known aliases (for example paperclipListAgents → list_agents, paperclipGetAgent → get_agent, paperclipListIssues → search_tasks, paperclipCreateIssue → create_task).

Collapse decisions executed by TASK-17039

  1. One source of truth. src/tools/ and src/semantic-tools/ no longer declare independent operation lists; both project CAPABILITY_CANONICAL_OPERATIONS. Placement, optional group, required claims, task modes, allowed roles, side-effect class, idempotency, and disabled-by-default are single-sourced. Bidirectional parity checks fail the build on any drift between a catalog's presentation and the canonical surface.
  2. generic_api_request claim unified to test:generic_api_request (scenario callers/tests updated). It stays test_only and is excluded from product capability coverage.
  3. One canonical task-mode policy (live runtime policy ∪ skill_test); the ledger's 15 task-mode divergences are resolved to zero.
  4. Input schema unified as one contract, projected two ways — idempotency in-band with provider bounds for the model, out-of-band for the observable scenario runtime — recorded as the single reviewed intentional projection.
  5. Placement of scenario-only (13) and live-only (4) operations retained. The 13 scenario-only ops stay scenario_mock (eval-only via mock extensions); the 4 live-only reads/continuation ops (get_agent, get_approval, get_approval_context, schedule_wake) stay live_codex with no scenario projection. No operation crossed surfaces this increment; a future real-service binding (deliverable G) is where scenario-only ops would gain a live binding.

Consumed by the real-surface-ledger (deliverable B) and eval (deliverable F) tasks: the live contract golden is unchanged; the only behavioral delta is the allowedModes skill_test addition described above.

Verification

  • src/catalog/reconciliation.test.ts — pins the op-set relationship, asserts both catalogs derive their operation set from the canonical source, asserts claims/modes/placement are single-sourced (no divergence), and requires a reviewed disposition for the surviving input-schema projection.
  • src/catalog/catalog-docs.test.ts — recomputes the catalog counts and membership in docs/capability-semantic-tools.md from the catalog so a stale hand count fails.
  • Live golden byte-identity checked by check:semantic-contracts; the scenario and live runtime behavior is covered by the test:scenarios suites.