Skip to content

finding: consumer half of #6523 — three plugin implementations still annotate SharingExecutionContext, so (context as any).posture is still needed to read a field the contract now declares #7070

Description

@os-zhuang

Out-of-scope observation from implementing #6523 (PR #7068), filed rather than fixed — the card was scoped to the contract face and explicitly forbade touching the implementation bodies, exactly as #6430's contract half and its plugin half were separated.

Blocked-by: #6523

Fact

#6523 / PR #7068 converged 36 contract signatures onto the full ExecutionContext. The three implementations behind those contracts still annotate their own method parameters with the six-field SharingExecutionContext, so nothing they read has widened. Measured on origin/main @ 08863dd18:

file SharingExecutionContext refs
packages/plugins/plugin-approvals/src/approval-service.ts 27
packages/plugins/plugin-sharing/src/sharing-service.ts 21
packages/plugins/plugin-reports/src/report-service.ts 14
packages/plugins/plugin-sharing/src/sharing-rule-service.ts 8
packages/plugins/plugin-sharing/src/exec-context-seam.testkit.ts 3
packages/plugins/plugin-audit/src/comment-access-hooks.ts 2
packages/plugins/plugin-approvals/src/approval-node.ts 2

The casts those narrow annotations force, all still present:

packages/plugins/plugin-approvals/src/approval-service.ts:661
  const posture = (context as any).posture;              // isOverrideActor()
packages/plugins/plugin-approvals/src/approval-service.ts:2773, 2813, 3259
  SYSTEM_CTX as unknown as SharingExecutionContext
packages/plugins/plugin-approvals/src/approval-node.ts:174
  } as unknown as SharingExecutionContext);
packages/plugins/plugin-sharing/src/exec-context-seam.testkit.ts:106
  return { ...authz, isSystem: false } as unknown as SharingExecutionContext;

:661 is the interesting one. Its own doc comment says the gate reads "the derived posture, ADR-0095" off the resolved exec context; the as any exists only because the declared type said the field was not there. After #6523 the contract declares it, so the cast is now removable — and until it is removed the expression stays unchecked, which is what an as any on an enforcement input costs: the next field read through the same expression is unverified too.

exec-context-seam.testkit.ts:106 is the double-cast twin — the helper resolves a REAL resolveAuthzContext envelope and then has to as unknown as it into the narrow type to hand it to the service.

What is NOT claimed here

Suggested shape (not a decision)

Re-annotate the implementation parameters to ExecutionContext, delete the casts that become redundant, and let SharingExecutionContext — which #6523 left exported and documented as migration residue precisely to keep these files compiling — become removable. Note (context as any).organizationId (approval-service.ts:1465, :3649, :3916) is a SEPARATE question: organizationId is not on ExecutionContext at all, and per #5858 / check:org-identifier that spelling has its own history. Do not fold it in without deciding it.

Dedup

Searched open issues: SharingExecutionContext (only #6523), ExecutionContext in title (only #6216). Not #6216 — that card is the three ASSEMBLY sites of ExecutionContext (producers); this is the consumption side of one contract family. Not inside #6523's completion scope, which the dispatch bounded to the contract face with implementations explicitly untouched, so this is standalone with a Blocked-by: rather than a sub-issue.

Related: #6206 (ruling), #6430 / PR #6511 (share-link half), #6523 / PR #7068 (this contract half), #6216.


Generated by Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions