Observation from implementing #7204 (PR #7283), filed rather than fixed — that card's file surface is plugin-reports, and this spans three packages plus wherever the shared home would be.
Fact
The same ~10-line helper, with the same name and the same doc-block reasoning, now exists in three copies:
Each declares its own const OPERATION_PRIVATE_KEY_PREFIX = '__' and its own function withoutOperationPrivateKeys(...). None is exported; every copy was written by hand from the previous one.
Why it is worth recording
The helper encodes a cross-package convention, not a local detail: __-prefixed keys on an execution context belong to the operation plugin-security has in flight, and a consumer forwarding an envelope elsewhere must drop them. The producer of that convention is packages/plugins/plugin-security (security-plugin.ts — sc.__readScope = …, __writeScope, the ADR-0090 D10 delegator halves, plus the engine's __expandRead / __referentialFieldClear markers). The rule about how to consume it lives in three copies in three other packages, and the package that produces the keys owns none of them.
Consequences, all latent today:
- A fourth consumer (any service that forwards a caller envelope to a gate or a read) is written by copy-paste or not at all, and nothing points a new author at the convention.
- If the middleware ever stamps something operation-private without a
__ prefix, three files have to change and there is no list of them.
- Each copy's doc block reasons about its own package's object (
sys_comment, sys_attachment, report.object_name), so the copies have already diverged in prose while agreeing in code — the shape that makes a later divergence in code hard to notice.
Why observation-class, not a defect
Nothing a user hits: all three copies are byte-equivalent in behaviour today, and each is covered by its own package's tests. This is a structural/ownership finding, so it carries finding and no pm:queue — grading is triage's call.
What I could not establish
Where the shared home should be. The candidates are not equivalent and the choice is a real one: @objectstack/spec (a constant + a pure function, but Prime Directive #2 says no business logic there — a key-filtering function may or may not count), @objectstack/core, or an export from plugin-security itself (the producer, which is the most honest owner but makes three packages depend on the security plugin for a string-prefix filter). Worth a decision rather than a guess.
Dedup
Searched open issues for withoutOperationPrivateKeys, __readScope + prefix/strip, and operation-private + envelope + helper/duplicate: no hits. #7141, #7145 and #7204 are the three landing sites and each is scoped to its own package; none of them covers the extraction.
Related: #7141, #7145, #7204, #6523, #6206 (ruling).
Generated by Claude Code
Observation from implementing #7204 (PR #7283), filed rather than fixed — that card's file surface is
plugin-reports, and this spans three packages plus wherever the shared home would be.Fact
The same ~10-line helper, with the same name and the same doc-block reasoning, now exists in three copies:
packages/plugins/plugin-audit/src/comment-access-hooks.ts:215(plugin-audit'scallerContextrebuilds a 5-field subset of the execution envelope, droppingonBehalfOfbefore the sharing gates that are documented to fail closed on it #7141 / PR fix(plugin-audit): forward the caller's execution envelope to the sys_comment sharing gates (#7141) #7143 — the original)packages/services/service-storage/src/attachment-access-hooks.ts:103(service-storage's attachment kit carries the same 5-fieldcallerContextprojection #7141 fixed for comments #7145 / PR fix(service-storage): forward the caller's execution envelope to the sys_attachment sharing gates (#7145) #7207 — copy 2)packages/plugins/plugin-reports/src/report-service.ts(plugin-reports'executeReportrebuilds a 5-field subset of the execution envelope, droppingaccessible_org_ids— agroup-posture report silently under-reports #7204 / PR fix(plugin-reports): forward the caller's execution envelope to the report read (#7204) #7283 — copy 3)Each declares its own
const OPERATION_PRIVATE_KEY_PREFIX = '__'and its ownfunction withoutOperationPrivateKeys(...). None is exported; every copy was written by hand from the previous one.Why it is worth recording
The helper encodes a cross-package convention, not a local detail:
__-prefixed keys on an execution context belong to the operation plugin-security has in flight, and a consumer forwarding an envelope elsewhere must drop them. The producer of that convention ispackages/plugins/plugin-security(security-plugin.ts—sc.__readScope = …,__writeScope, the ADR-0090 D10 delegator halves, plus the engine's__expandRead/__referentialFieldClearmarkers). The rule about how to consume it lives in three copies in three other packages, and the package that produces the keys owns none of them.Consequences, all latent today:
__prefix, three files have to change and there is no list of them.sys_comment,sys_attachment,report.object_name), so the copies have already diverged in prose while agreeing in code — the shape that makes a later divergence in code hard to notice.Why observation-class, not a defect
Nothing a user hits: all three copies are byte-equivalent in behaviour today, and each is covered by its own package's tests. This is a structural/ownership finding, so it carries
findingand nopm:queue— grading is triage's call.What I could not establish
Where the shared home should be. The candidates are not equivalent and the choice is a real one:
@objectstack/spec(a constant + a pure function, but Prime Directive #2 says no business logic there — a key-filtering function may or may not count),@objectstack/core, or an export fromplugin-securityitself (the producer, which is the most honest owner but makes three packages depend on the security plugin for a string-prefix filter). Worth a decision rather than a guess.Dedup
Searched open issues for
withoutOperationPrivateKeys,__readScope+ prefix/strip, and operation-private + envelope + helper/duplicate: no hits. #7141, #7145 and #7204 are the three landing sites and each is scoped to its own package; none of them covers the extraction.Related: #7141, #7145, #7204, #6523, #6206 (ruling).
Generated by Claude Code