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

Activity

  1. os-zhuang commented on Aug 9, 2026

    @os-zhuang
    ContributorAuthor

    Findings triage: HOLD (finding kept), and the routing question deferred last round is now decided: deliberately left unrouted, with the split plan recorded, rather than forcing one wrong label.

    Premise re-verified @ origin/main b88f5e8: the ref counts stand (approval-service.ts 27 / sharing-service.ts 21 / report-service.ts 14). The Blocked-by: #6523 upstream is satisfied — its contract half landed via PR #7068 — so nothing blocks a future promotion.

    Routing rationale: the work spans two lanes with zero shared files — domain:services (plugin-approvals 29 refs + plugin-reports 14) and domain:identity (plugin-sharing 32 + plugin-audit 2). A single domain:* would misroute half the diff, and the one-label rule is a rule. So the blank stays, and the promotion plan is a contract-first-style split: at promotion, open two per-lane cards —

    • services: approval-service.ts / approval-node.ts / report-service.ts re-annotation + cast deletion;
    • identity: sharing-service.ts / sharing-rule-service.ts / exec-context-seam.testkit.ts / comment-access-hooks.ts same;

    both referencing this card, with SharingExecutionContext's export removal riding whichever of the two lands second. The (context as any).organizationId reads stay out of both, per this card's own boundary (#5858 / check:org-identifier territory).

    Restart: promote (and split as above) when either lane next plans work in these files, or when a sweep batch wants two clean mechanical cards.

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

  2. claude commented on Aug 9, 2026

    @claude
    Contributor

    Findings round — held (finding kept), deliberately left unrouted; upstream re-verification done.

    • Post-unlock re-check: Blocked-by: #6523 is now satisfied (closed, completed). Per the rule that the unblocking merge is the likeliest to have fixed the card in passing, re-verified the file face on origin/main @ 9136327: all still present — SharingExecutionContext refs at 27 (approval-service.ts) / 21 (sharing-service.ts) / 14 (report-service.ts), and the (context as any).posture cast at approval-service.ts:661. The card is now actionable on its merits.
    • Why no domain:*: the fix face spans two lanes — plugin-approvals + plugin-reports (domain:services) and plugin-sharing + plugin-audit (domain:identity). Ambiguous-landing findings stay unrouted rather than mis-routed; at promotion this either splits per-domain (contract-first) or goes through the cross-domain exception path with a designated lane. Named in this round's close-out brief for the next grading pass.

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

  3. os-zhuang commented on Aug 9, 2026

    @os-zhuang
    ContributorAuthor

    Findings round — PROMOTED via the recorded split plan: this card is now the progress view (finding → tracking), and the work lives in two per-lane queue cards added as sub-issues:

    Rationale and provenance: the split shape is exactly the one recorded in the 14:26Z hold comment and re-affirmed in the 18:26Z one; the 18:19Z round's close-out brief directed this pass to decide the promotion shape. Per-domain split wins over the cross-domain exception because the two halves share zero files and are each independently mechanical — no coordination inside a single PR is needed, and the one-label-per-card rule stays intact. The only cross-half coupling — removal of the exported SharingExecutionContext type — is assigned to whichever half lands second (recorded in both sub-cards).

    Premise re-verified at origin/main @ 445a0c2 immediately before the split: all seven files hold their ref counts (27/21/14/8/3/2/2) and the (context as any).posture cast is live at approval-service.ts:661. The organizationId casts stay out of both halves, per this card's own boundary.

    This parent stays open as the coordination node (tracking keeps it out of triage scans) and closes when both sub-issues close.

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

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

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