Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .changeset/20596-plugin-approvals-provenance-anchors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'@objectstack/plugin-approvals': patch
---

Provenance comments in `plugin-approvals` were re-anchored

Comment and docblock lines under `src/` that cited tracker numbers which no
longer resolve on GitHub now cite the commit in this repository's history that
decided the matter, and say in their own words what was decided. Comments
only: no type, schema, export, log or refusal text, or runtime behaviour changes.
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ describe('openNodeRequest — organization attribution (cloud#1395, #10101)', ()
});

it('⛔ pins the sys_api_key divergence: stamps the DECLARED active_organization_id, and never treats an ADR-0066 org FK as the stamp', async () => {
// The credential table (#8287/#8778): unwalled by necessity, rows still
// The credential table (#8287, commit 7901b2dd2): unwalled by necessity, rows still
// ABOUT one organization under `tenancy.organizationField` — limb 0 wins
// over the disabled-tenancy opt-out.
const apiKey = makeFakeEngine({
Expand Down
2 changes: 1 addition & 1 deletion packages/plugins/plugin-approvals/src/approval-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import {
} from '@objectstack/spec/automation';
// [#7135] The full `resolveAuthzContext` envelope — what
// `IApprovalService.openNodeRequest` declares for its context parameter since
// #6523 (the #6206 ruling: no per-site subset contracts).
// commit aa4b90d9a (the full-envelope ruling: no per-site subset contracts).
import type { ExecutionContext } from '@objectstack/spec/kernel';
import type { ApprovalService } from './approval-service.js';
import { registerApprovalReviseNode } from './approval-revise-node.js';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -746,9 +746,9 @@ describe('ApprovalService (node era)', () => {
expect(req.pending_approvers).toEqual(['position:sales_manager']);
});

// ── the #8710 carve-out, asserted on THIS side (#8863) ──────────────────
// ── the commit 04d03c3a0 carve-out, asserted on THIS side (commit d200b016b) ──
//
// Maintainer ruling, 2026-08-15 (#8710, inheriting #8613), verbatim:
// Maintainer ruling, 2026-08-15 (commit 04d03c3a0, inheriting #8613), verbatim:
//
// > Access-conferring paths filter deactivated positions; addressing
// > paths do not.
Expand Down
28 changes: 14 additions & 14 deletions packages/plugins/plugin-approvals/src/approval-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ import type {
ResumeFailureReport,
} from '@objectstack/spec/contracts';
// [#7135] The full `resolveAuthzContext` envelope — what `IApprovalService`
// declares for every one of these context parameters since #6523 (the #6206
// ruling: enforcement adjudicates on the whole envelope, never a per-site
// declares for every one of these context parameters since commit aa4b90d9a (the
// full-envelope ruling: enforcement adjudicates on the whole envelope, never a per-site
// subset). Annotating the implementation with the retired six-field shape is
// what forced this file to cast its way out of its own contract to read
// fields the caller had already supplied.
Expand All @@ -60,7 +60,7 @@ import { isFileIdToken, referenceTargetOf } from '@objectstack/spec/data';
// [#11993] The SANCTIONED renderer for OPERATION-level refusal copy. The
// Operation Message Catalog is the ONE seat for these sentences — its own
// header bars both a package-local string table and a second rendering
// mechanism for a second producer, and #12493 landed this service's key
// mechanism for a second producer, and commit aa5994e17 landed this service's key
// (`approval_recall_not_submitter`) into it ahead of this consumer half.
import { renderOperationMessage, type ValidationMessageTranslator } from '@objectstack/spec/system';
import { isGrantActive } from '@objectstack/core';
Expand Down Expand Up @@ -218,7 +218,7 @@ export interface ApprovalResumeSurface {
* evidence of anything. Rejects when a store cannot be read; the inspection
* counts such a row `undetermined` — but ⛔ unlike a thrown
* {@link hasSuspendedRun} it does NOT drop the row, because this oracle is
* asked only WHICH shape a row already known to be stranded is (#16709).
* asked only WHICH shape a row already known to be stranded is (commit 8c7cca1ce).
* A host that resolves a malformed verdict is treated the same way, and
* costs no OTHER row its answer.
*/
Expand Down Expand Up @@ -657,7 +657,7 @@ function refineFailedRunState(verdict: ConsumedSuspensionVerdict): StrandedRunSt
* was asked and could not answer. Three ways in: the attached surface has
* no `inspectConsumedSuspension` (an engine build older than this plugin,
* or a test double); the read THREW (a store outage); or the host resolved
* a malformed verdict, violating its own declared surface (#16709). Today's
* a malformed verdict, violating its own declared surface (commit 8c7cca1ce). Today's
* undifferentiated label, kept on purpose as the fail-closed fallback
* (#15358 ruling, item 1): a failure to differentiate is not evidence, so
* the row is reported and its repairability left unstated — ⛔ never
Expand Down Expand Up @@ -1378,7 +1378,7 @@ export class ApprovalService implements IApprovalService {
const perms = Array.isArray(context.permissions) ? context.permissions : [];
// [#7135] A DECLARED read. `posture` (ADR-0095 D2) is resolved by
// `resolveAuthzContext` and is a field of the envelope the contract has
// named here since #6523 — the doc block above already says it is the
// named here since commit aa4b90d9a — the doc block above already says it is the
// intended signal. Until this parameter widened, reading it meant an
// unchecked `as any` on an enforcement input: a typo (`postures`,
// `'PLATFORM-ADMIN'`) would have compiled and silently denied every
Expand Down Expand Up @@ -2292,7 +2292,7 @@ export class ApprovalService implements IApprovalService {
* `plugin-sharing`, whatever the shared method name suggests. Both answer
* "who holds position P"; this one reads the directory RAW — neither the
* ADR-0091 D2 validity window nor the `sys_position.active` catalogue flag is
* applied. Maintainer ruling, 2026-08-15 (#8710, inheriting #8613), verbatim:
* applied. Maintainer ruling, 2026-08-15 (commit 04d03c3a0, inheriting #8613), verbatim:
*
* > Access-conferring paths filter deactivated positions; addressing paths
* > do not.
Expand All @@ -2315,7 +2315,7 @@ export class ApprovalService implements IApprovalService {
* projects `user_id` too). The table carries no window columns at all and
* `isGrantActive` reads an absent bound as unbounded, so there is nothing
* a filter could do here; membership tier names have no `sys_position`
* row either (#8710's "a name with no row is untouched" fallback), so no
* row either (commit 04d03c3a0's "a name with no row is untouched" fallback), so no
* catalogue flag either. This limb cannot be brought into parity by
* adding a filter — see {@link expandMembershipTierUsers}.
* 3. `sys_position.active` — the sharing engine's gate for it lives at the
Expand All @@ -2326,7 +2326,7 @@ export class ApprovalService implements IApprovalService {
* The omission is per-READ, not a missing dependency: `isGrantActive` is
* imported in this file and IS applied to `sys_approval_delegation` in
* {@link lookupActiveDelegation}. ⛔ So do not "fix" this by adding the window
* filter here — that is the option #8710 rejected, on the reasoning above.
* filter here — that is the option the ruling (commit 04d03c3a0) rejected, on the reasoning above.
*/
private async expandPositionUsers(positionName: string, organizationId?: string | null): Promise<string[]> {
if (!positionName) return [];
Expand Down Expand Up @@ -2360,7 +2360,7 @@ export class ApprovalService implements IApprovalService {
* filter even if it were not: `sys_member` carries no ADR-0091 D2 window
* columns, and a tier name has no `sys_position` row to read `active` off.
* {@link expandPositionUsers} carries the ruling both reads inherit
* (#8613 / #8710) — this method is also the second limb of that union, so a
* (#8613 / commit 04d03c3a0) — this method is also the second limb of that union, so a
* change here changes position routing too.
*/
private async expandMembershipTierUsers(tier: string, organizationId?: string | null): Promise<string[]> {
Expand Down Expand Up @@ -4793,7 +4793,7 @@ export class ApprovalService implements IApprovalService {
* A surface without that member leaves the row `'failed'` — reported,
* undifferentiated — because absence of the discriminator is not evidence
* of anything. So does a read that THREW or answered a malformed verdict
* (#16709): by the time this oracle is asked the row is already known to be
* (commit 8c7cca1ce): by the time this oracle is asked the row is already known to be
* stranded, so a failure to differentiate it is not a reason to drop it from
* a report — it is counted `undetermined` as telemetry AND reported.
*
Expand All @@ -4820,7 +4820,7 @@ export class ApprovalService implements IApprovalService {
* outage must not be published as a lost run); a thrown or malformed THIRD
* read leaves its row in `stranded` as the undifferentiated `'failed'` and
* is counted here as well — the row is known to be stranded, only its
* shape could not be told (#16709). So this counter and `stranded.length`
* shape could not be told (commit 8c7cca1ce). So this counter and `stranded.length`
* overlap on purpose, and neither one alone sizes the scan's blind spot.
*/
undetermined: number;
Expand Down Expand Up @@ -4890,7 +4890,7 @@ export class ApprovalService implements IApprovalService {
// the other two oracles. See `refineFailedRunState` and
// `StrandedRunState` for the three answers and why none is folded.
if (runState === 'failed' && typeof this.automation.inspectConsumedSuspension === 'function') {
// ⚠️ [#16709 item 3] The REFINEMENT runs inside this `try`, with the
// ⚠️ [commit 8c7cca1ce, item 3] The REFINEMENT runs inside this `try`, with the
// read it refines. `refineFailedRunState` dereferences the verdict, so
// a host that violates the declared surface — resolving `undefined`
// where a verdict is declared — used to throw a `TypeError` out of
Expand All @@ -4903,7 +4903,7 @@ export class ApprovalService implements IApprovalService {
try {
refined = refineFailedRunState(await this.automation.inspectConsumedSuspension(runId));
} catch (err: any) {
// [#16709 item 2 — PM ruling, 2026-09-08] The row STAYS in the
// [commit 8c7cca1ce, item 2 — PM ruling, 2026-09-08] The row STAYS in the
// report, as the undifferentiated `'failed'`. This oracle is not
// asked WHETHER the row is stranded: the first two already answered
// that (no live pause, terminal `failed`). It is asked only WHICH of
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.

/**
* The one-off platform-row organization backfill (#11308) — dry run and write.
* The one-off platform-row organization backfill (commit 5a916c4d4) — dry run and write.
*
* The three properties the 2026-08-23 maintainer ruling names are asserted
* here rather than described anywhere:
Expand All @@ -14,9 +14,9 @@
* 3. **Idempotent** — the sweep runs twice against the same engine and the
* second run's write count is asserted to be 0.
*
* Plus the one thing this card must not do: a platform row about a
* Plus the one thing this sweep must not do: a platform row about a
* `sys_api_key` is repaired from `active_organization_id` (limb 0,
* stamp-only, #8778), and the credential table is never written to. A sweep
* stamp-only, commit 7901b2dd2), and the credential table is never written to. A sweep
* that "unified everything onto one organization field" would flatten that
* fork, so it is pinned rather than trusted.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*
* ## What this repairs, and what it deliberately does not
*
* #10101 (landed as PR #11311) fixed the WRITERS: a `sys_approval_request` and
* #10101 (landed as commit 1272f0a6b) fixed the WRITERS: a `sys_approval_request` and
* a `sys_automation_run` are now stamped from the SUBJECT record's own
* organization, with the acting context as the ruled fallback. It wrote
* nothing to existing rows, so the population produced before it persists —
Expand All @@ -32,7 +32,7 @@
* ONE shared resolver (`createRecordOrganizationResolver`,
* `@objectstack/metadata-core`) — never hard-coded to `organization_id`. That
* is what keeps `sys_api_key`'s deliberate divergence intact: its
* `tenancy.organizationField: 'active_organization_id'` (stamp-only, #8778)
* `tenancy.organizationField: 'active_organization_id'` (stamp-only, commit 7901b2dd2)
* wins limb 0 of the resolver, so a platform row ABOUT an API key is repaired
* from that column, and the credential table itself is never written to. A
* sweep written on the intuition "unify everything onto one organization
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
* #7135 — compile-time pin for the CONTEXT type this plugin's enforcement
* methods accept.
*
* #6523 converged 36 contract signatures onto the full `ExecutionContext` (the
* #6206 ruling: enforcement adjudicates on the whole `resolveAuthzContext`
* Commit aa4b90d9a converged 36 contract signatures onto the full `ExecutionContext` (the
* full-envelope ruling: enforcement adjudicates on the whole `resolveAuthzContext`
* envelope, never a per-site subset). #7135 is the services half of the #7070
* consumer split — the implementations here now annotate their own parameters
* with that same envelope instead of the six-field shape they used to name.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
/**
* #11286 — CONTRACT: the two `managerIsProvablyOutsideOrg` screens are EQUAL.
* Commit b019891cd — CONTRACT: the two `managerIsProvablyOutsideOrg` screens are EQUAL.
*
* `sys_user.manager_id` is read by two packages, and each screens the manager
* it finds against the caller's organization with its OWN implementation:
Expand Down Expand Up @@ -55,10 +55,10 @@
*/
import { describe, it, expect } from 'vitest';
import { ApprovalService } from './approval-service.js';
// [#11286] plugin-sharing's screen is reached by RELATIVE SOURCE PATH, and that
// [commit b019891cd] plugin-sharing's screen is reached by RELATIVE SOURCE PATH, and that
// is the only way in: it is deliberately NOT exported from that package's index
// (exporting it would hoist a security screen into another plugin's public API
// surface — the very decision this card is fenced out of), and the package's
// surface — the very decision this pin is fenced out of), and the package's
// `exports` map publishes `.` only, so there is no subpath to import. The read
// escapes this package, so it is declared in `CROSS_PACKAGE_TEST_INPUTS` in
// scripts/check-cross-package-test-inputs.mjs and mirrored into the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
*
* The refusal now renders through the shared Operation Message Catalog
* (`@objectstack/spec/system`, key `approval_recall_not_submitter`, landed by
* #12493) instead of a package-local string.
* commit aa5994e17) instead of a package-local string.
*
* ⚠️ These tests assert the SENTENCE AN OPERATOR READS, in zh-CN specifically.
* Asserting only that a catalog key was passed would pass against a message
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ import { ApprovalService } from './approval-service.js';
import { SysApprovalRequest } from './sys-approval-request.object.js';
import { SysApprovalAction } from './sys-approval-action.object.js';
import { SysApprovalApprover } from './sys-approval-approver.object.js';
// [#11081] `@objectstack/runtime`'s shared expected-noise capture. This import
// [commit c28e4cfae] `@objectstack/runtime`'s shared expected-noise capture. This import
// escapes the package on PURPOSE, so it is DECLARED rather than left for CI to
// discover: `CROSS_PACKAGE_TEST_INPUTS` in
// `scripts/check-cross-package-test-inputs.mjs` names the one file, and
Expand All @@ -59,7 +59,7 @@ import { captureExpectedReadRefusals } from '../../../runtime/src/expected-read-
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));

/**
* [#11081] The tables this fixture deliberately never provisions — and so the
* [commit c28e4cfae] The tables this fixture deliberately never provisions — and so the
* ONLY read refusals whose log frames may be withheld here.
*
* `beforeEach` boots a kernel with no datasource and attaches sqlite late, then
Expand Down Expand Up @@ -193,11 +193,11 @@ const authzResolverObjects = [
},
] as const;

/** [#11081] Shared by both kernels this file boots; asserted once in `afterAll`. */
/** [commit c28e4cfae] Shared by both kernels this file boots; asserted once in `afterAll`. */
const noise = captureExpectedReadRefusals([...EXPECTED_ABSENT_PROBE_TABLES]);

/**
* [#11081] The PIN half. ⛔ Repairing a failure here means re-deriving the list
* [commit c28e4cfae] The PIN half. ⛔ Repairing a failure here means re-deriving the list
* above or finding out why a probe stopped firing — NEVER deleting the channel.
* In particular a silent `sys_approval_delegation` means the out-of-office
* delegation lookup stopped running on a decision, which is a finding.
Expand Down Expand Up @@ -294,7 +294,7 @@ describe('an approval decision cascades as the deciding user (#3783)', () => {
// The engine's own `init()` ran during bootstrap, before this driver
// existed, so the connect the engine would have done is done here.
const driver = makeSqliteDriver();
// [#11081] Before `connect()` — i.e. before the driver runs any statement.
// [commit c28e4cfae] Before `connect()` — i.e. before the driver runs any statement.
// The sink also RESTORES a loud channel: an unexpected driver fault reaches
// the real console from here even though the kernel logger is `silent`.
noise.captureDriver(driver);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ function automation(opts: {
repairabilityThrowsFor?: string[];
/**
* Runs whose host RESOLVES `undefined` — a contract-violating implementation
* of its own declared surface (#16709 item 3). ⛔ Deliberately outside
* of its own declared surface (commit 8c7cca1ce, item 3). ⛔ Deliberately outside
* `Verdict`: pinning what happens when a host lies is the whole point, and
* the cast that makes it expressible is confined to this double.
*/
Expand Down Expand Up @@ -621,7 +621,7 @@ describe('#15358 — the third oracle splits `failed` three ways, and its ABSENC
});
});

// ── #16709: a failure to DIFFERENTIATE never costs a row its place, and never
// ── commit 8c7cca1ce: a failure to DIFFERENTIATE never costs a row its place, and never
// costs another row its answer ─────────────────────────────────────────────
//
// Two residues of the #15358 contract review, ruled together (PM seat,
Expand Down
Loading
Loading