Skip to content

feat(inspect): explain selected and omitted host components per target (#100) - #390

Merged
ScriptedAlchemy merged 2 commits into
mainfrom
feat/100-inspect-components
Sep 3, 2026
Merged

feat(inspect): explain selected and omitted host components per target (#100)#390
ScriptedAlchemy merged 2 commits into
mainfrom
feat/100-inspect-components

Conversation

@ScriptedAlchemy

@ScriptedAlchemy ScriptedAlchemy commented Sep 3, 2026

Copy link
Copy Markdown
Owner

Summary

#100 acceptance: "Inspect output explains selected, degraded, unavailable, and omitted components per target." Inspection previously reported only an omitted list with an enum cause and the human inspect output printed no component accounting at all.

  • InspectionPlan.selected lists the components each target emits, in the same deterministic order as skipped (additive; skipped is unchanged in shape).
  • Every accounted component that needs a host capability (skills, commands, rules, hooks, MCP servers/Apps) carries capability: the target's own four-state judgment — { name, state: 'supported', evidence } for emitted surfaces, { name, state: 'degraded' | 'unavailable' | 'prohibited', reason } for omissions — so the JSON explains why a rule is absent from a Claude bundle in the host's pinned words. Author exclusions (excluded-by-targets) still report first and carry the judgment the host would have applied. Scripts need no capability and carry none.
  • An adapter that publishes no row for a needed capability reads as an honest unavailable (The <target> adapter publishes no <capability> capability row.) instead of a bare boolean false.
  • Human inspect prints <target>: N component(s) selected, M omitted followed by omitted <kind> <name>: <cause> lines, with the capability state and reason for capability-driven omissions (exhaustive never switches over reason and state).
  • Docs: new "agent-bundle inspect component accounting" section in docs/entry-conventions.md; README inspect row. Changeset: agent-bundle minor.

Evidence

  • packages/agent-bundle/tests/api.test.ts — synthetic-registry test pins the honest missing-row unavailable judgment and empty selected; the five-target skip-accounting test now asserts selected per target (portable emits only the skill; Cursor emits commands and rules with evidence.target: 'cursor'; Claude emits commands but omits rules unavailable), capability details on capability-driven and author-driven omissions, no capability on scripts, frozen selected, and selected + skipped totals equal across targets. 34/34.
  • packages/agent-bundle/tests/cli.test.ts — new "explains selected and omitted components per target on human inspect output": real CLI process, portable: 1 component(s) selected, 1 omitted, omitted rule shared: rules unavailable — …, and the --json form carrying selected/skipped with judgments. cli file green in the same run (api+cli 46 passed before the one assertion fix, api 34/34 after).
  • pnpm typecheck green, pnpm lint 0/0, pnpm test:projection 63/63.
  • pnpm test:unit 2668 passed / 3 failed and pnpm test:route-unit 34/35: the failures are event-ipc live-server race, mcp-probe-service teardown timing, native-claude-contract and lifecycle-replay 5s timeouts, and the dispatcher 150ms elapsed-deadline test — all timing tests, none touching inspect; the box is at load average ~138 with a dozen lanes running. CI is the arbiter here.

Test plan

  • api + cli integration, typecheck, lint, projection
  • CI

Addendum

Second commit documents the #100 stage-2 component diagnostics that were live in source but absent from docs/diagnostics.md: rules AB4900AB4906 and commands AB4920AB4926 (code-family row plus a per-code table with triggers and recovery), including the explicit-target capability errors that make unsupported components fail before artifact publication.

@changeset-bot

changeset-bot Bot commented Sep 3, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 2496018

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
agent-bundle Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 3, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-03T05:57:22.309816Z 990669e PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 990669e7e1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +590 to +594
return Object.freeze({
name: component.capability,
...(state ?? unavailableCapability(
`The ${target} adapter publishes no ${component.capability} capability row.`,
)),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Project only declared capability fields into inspection

When an advanced TargetRegistry uses a JavaScript or third-party adapter whose otherwise-valid CapabilityState has enumerable extension fields, isCapabilityState accepts it but this spread copies those fields into the public inspection. For example, an extension field named name overrides the canonical capability name set above, while a circular extension value makes inspect --json fail during stableJson serialization. Construct the discriminated capability output from its contract fields and assign the canonical name last rather than spreading the adapter-owned object.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Agreed — addressed in follow-up #409 (2d1cd86). componentCapabilityFor now builds the output from the four-state contract fields only (capabilityContract/capabilityEvidenceContract) and assigns the canonical name last. api.test.ts covers adapter rows decorated with name: 'shadow' and a cyclic extension field: inspection reports exactly the contract fields with the canonical name and JSON.stringify succeeds.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed on main by #409 (62138ef, the #100 follow-up lane): componentCapabilityFor projects only the four-state contract fields (capabilityContract, exhaustive over state) and assigns the canonical name last; api.test.ts covers a decorated row with a name collision and a cyclic value. #408 carried an equivalent projection and dropped it in favour of #409 during rebase.

@pkg-pr-new

pkg-pr-new Bot commented Sep 3, 2026

Copy link
Copy Markdown
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle@390
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle/create-agent-bundle@390
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle/@agent-bundle/runtime@390

commit: 1492816

#100)

Inspection plans now list selected components beside skipped ones, and every
component that needs a host capability carries the target's own four-state
judgment — supported with pinned evidence, or degraded/unavailable/prohibited
with the host's reason — so inspect explains omissions in the host's words.
An adapter with no row for a needed capability reads as an honest
unavailable. Human inspect output prints one accounting line per target and
each omission with its reason.
@ScriptedAlchemy
ScriptedAlchemy force-pushed the feat/100-inspect-components branch from 1492816 to 2496018 Compare September 3, 2026 06:17
@ScriptedAlchemy
ScriptedAlchemy merged commit 1a365cf into main Sep 3, 2026
4 checks passed
ScriptedAlchemy added a commit that referenced this pull request Sep 3, 2026
#379/#385/#390

- dev: lease the adopted epoch in EpochAdoptionPolicy until replaced or closed;
  select the contract-matrix target from the server's own target list; apply the
  session timeout per matrix request; observe lifecycle progress through the
  session trace via a new ContractMatrixClient.observeProgress seam (#385)
- playground: wait for a hard-link catalog publisher to release its staging link
  before adopting the sidecar; return to discovery when the publication is
  rolled back (#377)
- build: run the Agent Plugins byte lane over portable/ during ordinary artifact
  validation; reject every forbidden control character in header values (#373)
- events/hooks: Codex PostToolUse accepts any present JSON tool_response (#378)
- api: project only contract fields of adapter capability rows in inspect (#390)
- tests/support: digest the real Claude home in the live session guard; isolate
  USERPROFILE alongside HOME (#374)
- docs: Claude plugin-root cwd exception, parked-pin trigger independence,
  provider typing contract, portable validation moments (#368/#379/#382/#373)
ScriptedAlchemy added a commit that referenced this pull request Sep 3, 2026
#379/#385/#390

- dev: lease the adopted epoch in EpochAdoptionPolicy until replaced or closed;
  select the contract-matrix target from the server's own target list; apply the
  session timeout per matrix request; observe lifecycle progress through the
  session trace via a new ContractMatrixClient.observeProgress seam (#385)
- playground: wait for a hard-link catalog publisher to release its staging link
  before adopting the sidecar; return to discovery when the publication is
  rolled back (#377)
- build: run the Agent Plugins byte lane over portable/ during ordinary artifact
  validation; reject every forbidden control character in header values (#373)
- events/hooks: Codex PostToolUse accepts any present JSON tool_response (#378)
- api: project only contract fields of adapter capability rows in inspect (#390)
- tests/support: digest the real Claude home in the live session guard; isolate
  USERPROFILE alongside HOME (#374)
- docs: Claude plugin-root cwd exception, parked-pin trigger independence,
  provider typing contract, portable validation moments (#368/#379/#382/#373)
ScriptedAlchemy added a commit that referenced this pull request Sep 3, 2026
#379/#385/#390

- dev: lease the adopted epoch in EpochAdoptionPolicy until replaced or closed;
  select the contract-matrix target from the server's own target list; apply the
  session timeout per matrix request; observe lifecycle progress through the
  session trace via a new ContractMatrixClient.observeProgress seam (#385)
- playground: wait for a hard-link catalog publisher to release its staging link
  before adopting the sidecar; return to discovery when the publication is
  rolled back (#377)
- build: run the Agent Plugins byte lane over portable/ during ordinary artifact
  validation; reject every forbidden control character in header values (#373)
- events/hooks: Codex PostToolUse accepts any present JSON tool_response (#378)
- api: project only contract fields of adapter capability rows in inspect (#390)
- tests/support: digest the real Claude home in the live session guard; isolate
  USERPROFILE alongside HOME (#374)
- docs: Claude plugin-root cwd exception, parked-pin trigger independence,
  provider typing contract, portable validation moments (#368/#379/#382/#373)
ScriptedAlchemy added a commit that referenced this pull request Sep 3, 2026
#379/#385/#390

- dev: lease the adopted epoch in EpochAdoptionPolicy until replaced or closed;
  select the contract-matrix target from the server's own target list; apply the
  session timeout per matrix request; observe lifecycle progress through the
  session trace via a new ContractMatrixClient.observeProgress seam (#385)
- playground: wait for a hard-link catalog publisher to release its staging link
  before adopting the sidecar; return to discovery when the publication is
  rolled back (#377)
- build: run the Agent Plugins byte lane over portable/ during ordinary artifact
  validation; reject every forbidden control character in header values (#373)
- events/hooks: Codex PostToolUse accepts any present JSON tool_response (#378)
- api: project only contract fields of adapter capability rows in inspect (#390)
- tests/support: digest the real Claude home in the live session guard; isolate
  USERPROFILE alongside HOME (#374)
- docs: Claude plugin-root cwd exception, parked-pin trigger independence,
  provider typing contract, portable validation moments (#368/#379/#382/#373)
ScriptedAlchemy added a commit that referenced this pull request Sep 3, 2026
* fix(runtime,test,inspect): require provider fixtures where providers do not run; project only capability contract fields (#95, #100 review follow-ups)

* chore(changeset): follow the changeset summary convention (#409)

* chore(changeset): classify the required provider fixtures as a pre-1.0 minor (#409)
ScriptedAlchemy added a commit that referenced this pull request Sep 3, 2026
#379/#385/#390

- dev: lease the adopted epoch in EpochAdoptionPolicy until replaced or closed;
  select the contract-matrix target from the server's own target list; apply the
  session timeout per matrix request; observe lifecycle progress through the
  session trace via a new ContractMatrixClient.observeProgress seam (#385)
- playground: wait for a hard-link catalog publisher to release its staging link
  before adopting the sidecar; return to discovery when the publication is
  rolled back (#377)
- build: run the Agent Plugins byte lane over portable/ during ordinary artifact
  validation; reject every forbidden control character in header values (#373)
- events/hooks: Codex PostToolUse accepts any present JSON tool_response (#378)
- api: project only contract fields of adapter capability rows in inspect (#390)
- tests/support: digest the real Claude home in the live session guard; isolate
  USERPROFILE alongside HOME (#374)
- docs: Claude plugin-root cwd exception, parked-pin trigger independence,
  provider typing contract, portable validation moments (#368/#379/#382/#373)
ScriptedAlchemy added a commit that referenced this pull request Sep 3, 2026
#379/#385/#390

- dev: lease the adopted epoch in EpochAdoptionPolicy until replaced or closed;
  select the contract-matrix target from the server's own target list; apply the
  session timeout per matrix request; observe lifecycle progress through the
  session trace via a new ContractMatrixClient.observeProgress seam (#385)
- playground: wait for a hard-link catalog publisher to release its staging link
  before adopting the sidecar; return to discovery when the publication is
  rolled back (#377)
- build: run the Agent Plugins byte lane over portable/ during ordinary artifact
  validation; reject every forbidden control character in header values (#373)
- events/hooks: Codex PostToolUse accepts any present JSON tool_response (#378)
- api: project only contract fields of adapter capability rows in inspect (#390)
- tests/support: digest the real Claude home in the live session guard; isolate
  USERPROFILE alongside HOME (#374)
- docs: Claude plugin-root cwd exception, parked-pin trigger independence,
  provider typing contract, portable validation moments (#368/#379/#382/#373)
ScriptedAlchemy added a commit that referenced this pull request Sep 3, 2026
#379/#385/#390

- dev: lease the adopted epoch in EpochAdoptionPolicy until replaced or closed;
  select the contract-matrix target from the server's own target list; apply the
  session timeout per matrix request; observe lifecycle progress through the
  session trace via a new ContractMatrixClient.observeProgress seam (#385)
- playground: wait for a hard-link catalog publisher to release its staging link
  before adopting the sidecar; return to discovery when the publication is
  rolled back (#377)
- build: run the Agent Plugins byte lane over portable/ during ordinary artifact
  validation; reject every forbidden control character in header values (#373)
- events/hooks: Codex PostToolUse accepts any present JSON tool_response (#378)
- api: project only contract fields of adapter capability rows in inspect (#390)
- tests/support: digest the real Claude home in the live session guard; isolate
  USERPROFILE alongside HOME (#374)
- docs: Claude plugin-root cwd exception, parked-pin trigger independence,
  provider typing contract, portable validation moments (#368/#379/#382/#373)
ScriptedAlchemy added a commit that referenced this pull request Sep 3, 2026
#379/#385/#390

- dev: lease the adopted epoch in EpochAdoptionPolicy until replaced or closed;
  select the contract-matrix target from the server's own target list; apply the
  session timeout per matrix request; observe lifecycle progress through the
  session trace via a new ContractMatrixClient.observeProgress seam (#385)
- playground: wait for a hard-link catalog publisher to release its staging link
  before adopting the sidecar; return to discovery when the publication is
  rolled back (#377)
- build: run the Agent Plugins byte lane over portable/ during ordinary artifact
  validation; reject every forbidden control character in header values (#373)
- events/hooks: Codex PostToolUse accepts any present JSON tool_response (#378)
- api: project only contract fields of adapter capability rows in inspect (#390)
- tests/support: digest the real Claude home in the live session guard; isolate
  USERPROFILE alongside HOME (#374)
- docs: Claude plugin-root cwd exception, parked-pin trigger independence,
  provider typing contract, portable validation moments (#368/#379/#382/#373)
ScriptedAlchemy added a commit that referenced this pull request Sep 3, 2026
#379/#385/#390

- dev: lease the adopted epoch in EpochAdoptionPolicy until replaced or closed;
  select the contract-matrix target from the server's own target list; apply the
  session timeout per matrix request; observe lifecycle progress through the
  session trace via a new ContractMatrixClient.observeProgress seam (#385)
- playground: wait for a hard-link catalog publisher to release its staging link
  before adopting the sidecar; return to discovery when the publication is
  rolled back (#377)
- build: run the Agent Plugins byte lane over portable/ during ordinary artifact
  validation; reject every forbidden control character in header values (#373)
- events/hooks: Codex PostToolUse accepts any present JSON tool_response (#378)
- api: project only contract fields of adapter capability rows in inspect (#390)
- tests/support: digest the real Claude home in the live session guard; isolate
  USERPROFILE alongside HOME (#374)
- docs: Claude plugin-root cwd exception, parked-pin trigger independence,
  provider typing contract, portable validation moments (#368/#379/#382/#373)
ScriptedAlchemy added a commit that referenced this pull request Sep 3, 2026
#379/#385/#390

- dev: lease the adopted epoch in EpochAdoptionPolicy until replaced or closed;
  select the contract-matrix target from the server's own target list; apply the
  session timeout per matrix request; observe lifecycle progress through the
  session trace via a new ContractMatrixClient.observeProgress seam (#385)
- playground: wait for a hard-link catalog publisher to release its staging link
  before adopting the sidecar; return to discovery when the publication is
  rolled back (#377)
- build: run the Agent Plugins byte lane over portable/ during ordinary artifact
  validation; reject every forbidden control character in header values (#373)
- events/hooks: Codex PostToolUse accepts any present JSON tool_response (#378)
- api: project only contract fields of adapter capability rows in inspect (#390)
- tests/support: digest the real Claude home in the live session guard; isolate
  USERPROFILE alongside HOME (#374)
- docs: Claude plugin-root cwd exception, parked-pin trigger independence,
  provider typing contract, portable validation moments (#368/#379/#382/#373)
ScriptedAlchemy added a commit that referenced this pull request Sep 3, 2026
/#379/#385/#390) (#408)

* fix: address late review threads on merged PRs #368/#373/#374/#377/#378/#379/#385/#390

- dev: lease the adopted epoch in EpochAdoptionPolicy until replaced or closed;
  select the contract-matrix target from the server's own target list; apply the
  session timeout per matrix request; observe lifecycle progress through the
  session trace via a new ContractMatrixClient.observeProgress seam (#385)
- playground: wait for a hard-link catalog publisher to release its staging link
  before adopting the sidecar; return to discovery when the publication is
  rolled back (#377)
- build: run the Agent Plugins byte lane over portable/ during ordinary artifact
  validation; reject every forbidden control character in header values (#373)
- events/hooks: Codex PostToolUse accepts any present JSON tool_response (#378)
- api: project only contract fields of adapter capability rows in inspect (#390)
- tests/support: digest the real Claude home in the live session guard; isolate
  USERPROFILE alongside HOME (#374)
- docs: Claude plugin-root cwd exception, parked-pin trigger independence,
  provider typing contract, portable validation moments (#368/#379/#382/#373)

* fix(dev): lease before publishing contract status; align fixtures with the portable byte lane

- EpochAdoptionPolicy acquires the epoch lease before publishing a passed
  dev.contract.status and announces adoption synchronously with it, so a
  status reader never sees "passed" for an epoch that is not yet adopted
- hooks.test: Codex PostToolUse accepts a string tool_response and rejects a
  missing one; Claude keeps the object check
- mcp-session-service/public-api-packed fixtures: Agent Plugins forbids
  placeholders in headers and non-bare/non-./ commands, and ordinary artifact
  validation now enforces the standard, so the fixtures carry a literal header
  and a bare `node` command

* chore(changeset): drop the Codex tool_response bullet already released by #404

* fix(playground,test): withdraw a failed catalog publication before releasing its staging link; bind custom observeProgress

- #persistSnapshot rolls the sidecar back while the staging link still exists
  when the post-link directory fsync fails, so a concurrent reader keeps seeing
  an in-progress publication until the path is withdrawn instead of adopting a
  briefly singly linked file
- contractProgressObserver invokes a client's observeProgress method with the
  client as receiver

* chore(changeset): one-paragraph summary ending with the PR reference

* fix(playground): recover a catalog staging link abandoned by an exited publisher

After the settle deadline, a matching .stage-<pid>-* link whose publisher pid
no longer exists is an abandoned publication of an already fsynced sidecar:
withdraw the orphan and adopt the sidecar instead of rejecting the epoch
forever. A live publisher's staging link is still never yanked. Adds the
@internal catalogStagingSettleDeadlineMs seam for deterministic tests.

* fix(playground): fsync the catalog directory after withdrawing an abandoned staging link

* fix(dev): forward request _meta (progress token) through McpSession and the dev matrix client

Lifecycle fixtures pass their generated progressToken as params._meta; the
session adapter and McpSession.callTool dropped it, so generated routes never
enabled sendProgress and every progress-gated lifecycle fixture failed the dev
matrix. McpSessionToolCallOptions and McpClient.callTool now carry _meta.

* fix(dev,playground): restart the adoption drain after a handoff race; keep the staging link when a sidecar rollback fails

- EpochAdoptionPolicy reschedules its drain from the completion handler when a
  candidate arrived between the loop's last empty check and #processing being
  cleared, and settled() waits through restarts
- #persistSnapshot releases the staging link after a failed publication only
  once the owned sidecar is confirmed withdrawn, so a rollback failure never
  leaves a singly linked sidecar for readers to adopt

* ci: retrigger checks for the rebased head

* chore: drop the portable byte-lane changes superseded by #406; keep the _meta assertions

* fix(playground): restore the staging guard when a recovery fsync fails

* fix(playground): accept a concurrently restored staging guard (EEXIST aliasing the sidecar) during recovery

* fix(dev): recheck supersession after the adoption lease settles

* fix(playground): keep a fresh pid-owned guard when recovery can neither re-link nor withdraw the sidecar

* fix(playground): fsync every compensating recovery guard before trusting it
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.

1 participant