Conversation
url-parse was used only to build the OPA client base URL. Node's native WHATWG URL (available since v10; engines.node already requires >=10) does the same, so extract a buildOpaBaseUrl() helper and drop url-parse and @types/url-parse. yarn.lock is pruned of url-parse and its now-orphaned transitive dependencies (querystringify, requires-port) only; every other entry is left byte-for-byte unchanged.
Lock the exact OPA base URL produced for the default PDP, trailing-slash, explicit-port, https, and path-prefix inputs so the url-parse -> native URL refactor is proven behaviour-equivalent on valid input and any regression fails here; assert a scheme-less PDP (bare host or //host:port) throws; and assert the Enforcer wires the OPA client baseURL to buildOpaBaseUrl(pdp).
Pin actions/checkout (v7.0.0) and actions/setup-node (v6.4.0) to full commit SHAs in both workflows, set persist-credentials: false on all checkouts, and bump the CI node matrix from 18/20 to 20/22 (18 is EOL). Run the full suite on PRs/pushes, not only on release. Same-repo events provision a throwaway Permit env via PROJECT_API_KEY, run a dockerized PDP (now with -e PDP_API_KEY/PERMIT_API_KEY and a /healthy readiness wait), execute test:ci:full, and delete the env on always(). Fork and secret-less runs fall back to the no-backend test:ci:unit suite. Add the two supporting scripts and quote $GITHUB_ENV in the publish workflow. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace AVA 3 with Vitest 4.1 (vitest.config.ts with unit / module-imports
/ integration / e2e projects; backend projects run serially via forks +
maxWorkers=1 to avoid shared-env collisions). Keep test:ci:unit /
test:ci:full names so the CI workflow is unchanged.
Remove every timer-based propagation wait: a new waitFor/waitForCheck
helper polls the actual permit.check() until it converges, bounded by a
timeout, replacing the fixed sleep(10s) waits in the e2e suites.
Rewrite fixtures to a createTestClient() factory (handleApiError now
throws). Migrate all t.* assertions to expect. Module-import specs load
the built bundle (build/index.{js,mjs}) to keep packaging-regression
coverage. Wire in the two previously orphaned specs (bulk, lists) with
proper setup/cleanup; preserve bulkRelationshipTuples coverage. Keep the
inherently racy local_facts "skip wait" case as it.skip and add a
deterministic waitForSync header unit test. Drop ava/nyc/codecov/ts-node;
add vitest/@vitest/coverage-v8; bump @types/node to ^20; skipLibCheck for
Vitest's d.ts.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a shared mock seam (src/tests/helpers/mock-api.ts, createMockPermit) that patches the axios adapter on the REST, PDP and OPA transports and seeds API context without network, then add unit specs covering every API module (resources, roles, resource-roles, role-assignments, users, tenants, resource-instances, resource-relations, relationship-tuples, condition-sets, condition-set-rules, resource-actions/attributes/ action-groups, projects, environments, elements, deprecated), the enforcer (check/bulkCheck/getUserPermissions/checkAllTenants, string parsing, default-tenant, OPA path, response shaping, throwOnError) and the utils/config layer. Add one ABAC e2e (condition-sets) following the event-based, self-cleaning conventions. 262 new unit tests; full no-backend suite is 333 tests. Tests-only; no SDK source changes. Tests assert current behavior of two latent bugs (checkAllTenants payload PER-15318; unreachable PermitPDPStatusError), flagged in-code, not fixed here. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
checkAllTenants passed { headers, params } as the axios POST body (2nd
arg), so the Authorization header was never sent and the query was
nested under `params` instead of being the request body — the PDP could
neither authenticate nor read the request.
Mirror check(): send the normalized { user, action, resource, context }
as the body and pass headers/timeout as the axios config arg. Normalize
the string forms of user/resource but skip default-tenant injection,
since an all-tenants query must not be pinned to a tenant. Add an AVA
regression test asserting the auth header is sent, the body shape is
correct, and no tenant is injected.
Fixes PER-15318
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The e2e suites are AVA with fixed sleep(10s) waits and fail fast on the first error. Against a freshly started PDP they hit a momentary ECONNREFUSED window right after the write burst (OPA reload), which kills the whole run even though the env, key, and policy sync are all healthy (/healthy passes). Scope the PR backend run to the suite that reliably passes — unit + integration + module-imports (what `yarn test` runs, the same set the publish workflow runs). The event-based, error-tolerant e2e lands in the stacked test-migration PR, which re-includes e2e in CI. Also add a PDP diagnostics step (docker logs + container state + /healthy) on backend-run failure so PDP connection errors, which surface with no HTTP response, are debuggable. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…test-event-based-tests * per-15306/ci-pin-actions-tests-on-pr: ci: run unit/integration/module-imports on PR, defer e2e to next PR # Conflicts: # package.json
…rehensive-sdk-tests * per-15315/vitest-event-based-tests: ci: run unit/integration/module-imports on PR, defer e2e to next PR
Stacked PRs target feature branches, so a pull_request filter of branches:[main] meant they never ran CI. Drop the base-branch filter so every PR is tested regardless of base. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…test-event-based-tests * per-15306/ci-pin-actions-tests-on-pr: ci: run on all pull requests, not only those targeting main
…rehensive-sdk-tests * per-15315/vitest-event-based-tests: ci: run on all pull requests, not only those targeting main
Node resolves `localhost` to ::1 (IPv6) first, but the GitHub runner's Docker IPv6 port publish refuses connections, so e2e permit.check() calls hit ECONNREFUSED even though the PDP is healthy on IPv4 (curl /healthy returns 200). Set PDP_URL to http://127.0.0.1:7766 so the SDK uses the working IPv4 path, and pin the readiness probe to 127.0.0.1 too. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…test-event-based-tests * per-15306/ci-pin-actions-tests-on-pr: ci: pin PDP connection to IPv4 (127.0.0.1) in the backend test run
…rehensive-sdk-tests * per-15315/vitest-event-based-tests: ci: pin PDP connection to IPv4 (127.0.0.1) in the backend test run
The dockerized PDP in CI doesn't expose OPA (port 8181), so rbac's direct useOpa checks hit ECONNREFUSED. Gate them behind PERMIT_RUN_OPA_E2E (default off) so they only run against an OPA-exposed setup. Raise the rebac convergence gate to 150s and the e2e test timeout to 300s, since the heavy ReBAC graph needs longer to propagate cloud->PDP on a cold env. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rehensive-sdk-tests * per-15315/vitest-event-based-tests: test: make rbac useOpa checks opt-in and widen rebac CI budget
bulkCheck and getUserPermissions query separate PDP endpoints that can lag a single permit.check, so the direct assertions raced cloud->PDP propagation and flaked on the slower matrix leg. Gate the complete-user read and poll bulkCheck/getUserPermissions until they converge before asserting. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rehensive-sdk-tests * per-15315/vitest-event-based-tests: test: poll the rbac multi-result reads to remove propagation races
A userset condition set referencing user.<attr> requires that attribute to exist on the built-in user resource; users.sync alone doesn't register it, so the condition-set creation failed with 400 MISSING_RESOURCE_ATTRIBUTE. Register a run-unique attribute on the __user resource before creating the userset, reference it consistently in the condition and the synced users, and remove it in the tolerant afterAll. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Condition sets compile to new policy (rego), which propagates slower than role/fact writes, so the 60s default left the ABAC check timing out in CI before the policy took effect. Match the heavier rebac budget. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
PER-15318 Read allowed_tenants and return the tenant details. Merge the global context store into the request context, with caller keys taking precedence, as check() does. Replace adapter fixtures with real local HTTP tests for normalized POST bodies, authentication, SDK-language headers, attributes, empty decisions, and global context merging. Add a shared local PDP test server for these and later regression tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PER-16492 Merge each check's context over the method context before deriving the global context. Keep sibling checks and caller-owned contexts isolated. Add local HTTP regression coverage for precedence, optional method context, shallow merging, and unchanged inputs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PER-16494
Raise PermitPDPStatusError with statusCode and responseBody for HTTP
responses, including Axios rejections, in check, bulkCheck,
getUserPermissions and checkAllTenants. Preserve transport connection
errors.
HTTP error responses that Axios rejects, such as 401 and 500, used to
raise PermitConnectionError with a connection-failure message. Their
error name is now PermitPDPStatusError, and their message is the one
used for unexpected resolved statuses: "Permit.<method>() got an
unexpected status code: <status>, ...". The message does not include
the user, action or resource.
A 200 response with a body the SDK cannot read, such as {}, also used
to raise PermitConnectionError saying the SDK cannot connect to the
PDP. It now raises PermitPDPStatusError with statusCode 200, the raw
body in responseBody, and a message saying the PDP returned an
unexpected response body.
Make PermitPDPStatusError extend PermitConnectionError so existing
instanceof PermitConnectionError catches keep handling HTTP failures
that previously surfaced as connection errors. Keep one-argument
construction available; SDK-generated HTTP errors fill both new fields.
checkAllTenants no longer rethrows the raw AxiosError, which carried
the request config and its Authorization header. It maps PDP errors
like the other methods and, when throwing, logs each one once, without
the extra log in Permit.checkAllTenants. Like check and bulkCheck, it
applies the SDK throwOnError setting to every failure, including an
invalid resource string: with throwing disabled it logs the error and
returns an empty tenant list. With throwing disabled, bulkCheck
returns one false per input check instead of an empty array.
Cover 401, 500, unexpected resolved statuses, string response bodies,
unreadable 200 bodies, and transport timeouts for all four methods,
and invalid resource strings for the three methods that take a
resource, as separate tests, with per-call and global error-policy
overrides. Check that thrown errors contain neither the API key nor
user details.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PER-16493 Stop serializing SDK configuration in debug logs. Use plain Pino JSON for JSON mode. For pretty mode, write through a synchronous in-process pino-pretty stream instead of a Pino transport, so bundled apps need no worker-thread target and Permit instances add no process exit listeners. Keep JSON lines as the default output: log.json defaults to true. When log.json is omitted, PERMIT_LOG_JSON=false selects pretty output. The variable ignores letter case and surrounding whitespace, and any other value keeps JSON lines instead of making new Permit() throw. An explicit log.json always overrides the environment variable. Cover default, explicit and environment JSON and pretty settings with 12 instances each, PERMIT_LOG_JSON values and overrides, configured secret exclusion, and debug logging for successful calls, HTTP errors and connections the PDP closes without replying, for all four PDP methods, with throwing enabled and disabled. HTTP errors must surface as PermitPDPStatusError and closed connections as PermitConnectionError, and in JSON mode a thrown failure must produce exactly one error log record. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PER-16493 PER-16494 Add a Logging and errors section to the README. Describe log.level, the JSON default, how PERMIT_LOG_JSON is read, pretty output, and how an explicit log.json overrides the environment variable. Describe PermitPDPStatusError and PermitConnectionError, including unreadable 200 responses, the statusCode field and the raw responseBody, matching errors with instanceof, and what each PDP method returns when throwOnError is false. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Remove unused imports and constants from the e2e and module-import specs, and replace a non-null assertion with an equivalent type assertion. These warnings are pre-existing on main. There is no behaviour change: the emitted JavaScript differs only by two removed unused constants. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PER-16544 PermitApiError stored the raw AxiosError in its enumerable originalError field. The error's request config carried the Authorization header with the API key, and its Node request object carried the same header in its raw header block, so logging a failed REST call with util.inspect, JSON.stringify, pino's err serializer or an error tracker leaked the key. The deprecated permit.api methods rethrew the raw AxiosError, with the same exposure. Remove credentials from the Axios error before it is thrown. Reduce the request config to method, URL, params, body and timeout, redact the value of every request header except a short list that carries no credentials, redact the response Set-Cookie header, and drop the request objects. The status, response body, method and URL stay available for debugging. PermitApiError.request is now undefined. Cover 401 and 500 responses from a current and a deprecated REST method, and a connection reset, against a local server. Check that util.inspect, JSON.stringify and pino output contain neither the API key, a custom header secret nor a cookie, and that the useful fields remain. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PER-15306 PER-15315 PER-15317 Fold the stacked test and CI branches into this branch so the SDK fixes land together with the Vitest suite, the per-module unit tests and the CI changes. The merged head is #133 (a71e7ad), which contains #132 (64b288c) and #131 (fc2529b). Conflicts: - src/tests/e2e/lists.e2e.spec.ts, src/tests/e2e/rbac.e2e.spec.ts and src/tests/module-imports/esm-import.spec.ts: this branch only removed unused imports from the AVA versions. The stack rewrote these files for Vitest, so the stack's versions are kept. - src/tests/unit/config.spec.ts: both sides added the file. The stack's Vitest version is kept here; the next commit ports this branch's PERMIT_LOG_JSON cases into it. The SDK sources are this branch's; the stack did not touch them. The stack's package.json replaces AVA, nyc, ts-node, codecov and open-cli with Vitest, so this merge changes the dev dependencies and the lock file. This branch's AVA unit specs are ported to Vitest in the next commit, and the stack's tests that pin the old SDK behaviour are updated after that. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
URL validation accepts query and fragment components that cause configured API and PDP endpoints to be misrouted.
Review effort: Balanced
Findings: 1
Open (10)
Model monthly_tenants as string[] instead of Set<string> Reject URLs containing query strings or fragments · New Fix missing space and sentence break after “role” · New Fix missing verb in invitation description · New Remove repeated “that” in property description · New Remove repeated “that” in property description · New Remove repeated “that” in property description · New Replace invalid plural “Detaileds” in relationship description · New Replace invalid plural “Detaileds” in resource description · New Fix typo: change “Arbitraty” to “Arbitrary” · New
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
The release combines extensive public API, generated-contract, transport, build, and CI changes that require final human validation.
Review effort: Balanced
Findings: 1
Open (10)
Model monthly_tenants as string[] instead of Set<string> Reject URLs containing query strings or fragments Fix typo: change “Arbitraty” to “Arbitrary” Replace invalid plural “Detaileds” in resource description Replace invalid plural “Detaileds” in relationship description Remove repeated “that” in property description Remove repeated “that” in property description Remove repeated “that” in property description Fix missing verb in invitation description Fix missing space and sentence break after “role”
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
Primary-worktree hook installation can overwrite the shared default hook directory used by sibling worktrees.
Review effort: Balanced
Findings: 1
Open (9)
Model monthly_tenants as string[] instead of Set<string> Fix typo: change “Arbitraty” to “Arbitrary” Replace invalid plural “Detaileds” in resource description Replace invalid plural “Detaileds” in relationship description Remove repeated “that” in property description Remove repeated “that” in property description Remove repeated “that” in property description Fix missing verb in invitation description Fix missing space and sentence break after “role”
Resolved since last review (1)
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
It combines a major public API rebaseline with extensive generated code, packaging, build, security, and release-pipeline changes requiring final human validation.
Review effort: Balanced
Findings: 1
Resolved since last review (8)
Fix typo: change “Arbitraty” to “Arbitrary” Replace invalid plural “Detaileds” in resource description Replace invalid plural “Detaileds” in relationship description Remove repeated “that” in property description Remove repeated “that” in property description Remove repeated “that” in property description Fix missing verb in invitation description Fix missing space and sentence break after “role”
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
The semver-major change spans generated contracts, runtime behavior, packaging, CI, and security gates while release evidence still reports 12 unproved operations and pending CI.
Review effort: Balanced
Findings: 1



Summary
This release corrects permission-check payloads and context handling, makes SDK errors and logging safer, and moves the test suite to Vitest. It also sets the supported runtimes to Node
^22.13.0 || ^24.0.0, replaces Yarn with pinned pnpm 12.8.1, and checks authored and generated code with strict TypeScript, Oxlint and Oxfmt.Tracking: PER-16556. This description covers the implemented changes currently pushed to this PR.
SDK behavior
checkAllTenantssends an authenticated POST with the permission query in the body, normalizes users/resources, merges context, and does not inject a default tenant (PER-15318).bulkCheckrespects each item's context, followed by method and global context, without mutating caller inputs (PER-16492).PermitPDPStatusError; connection failures remainPermitConnectionError. WiththrowOnError: false, failed bulk checks return one denial per input and all-tenant checks return an empty list (PER-16494).url-parse. Invalid or empty PDP URLs fail during construction; dot segments are normalized. This includes @Kyzgor's contribution from refactor(deps): replace url-parse with the native URL API (PER-16497) #122 and closesurl-parseris an unnecessary dependency #106.Runtime and dependency management
Strict tooling and declaration integrity (PER-16558)
@ts-ignoresuppressions are removed; normalization has syntax/configuration checks and a final compiler gate.pnpm verifyruns the frozen dependency check, lint, formatting, strict types, both builds and local tests. CI runs these checks as explicit required candidate jobs, followed by packed-consumer and security gates.Reviewed OpenAPI contract (PER-16560)
EnvironmentCopyConflictStrategyEnumbecomesEnvironmentCopyConflictStrategy. Required tenant fields, current role models and generated-only removals are documented in the migration inventory.PDP response contracts (PER-16562)
PermitPDPStatusErroror use the existing configured denial fallback. Per-call error policy remains supported where already exposed, and a zero timeout is preserved.useOpa: truefor bulk and permission calls produces an explicit SDK error before HTTP instead of being ignored.check()retains direct OPA support. The README documents these next-major behavior changes.HTTP ownership and retries (PER-16563)
allowAbsoluteUrls: truefor SDK requests; direct caller requests retain their own settings. Intentional caller hooks and caller-owned retries remain under caller control.Mixed Axios entries (PER-16669)
false/nullsuppression values. Request/response hooks and transforms run once per attempt; direct caller requests keep their settings.Configuration and API context (PER-16564)
Base URL validation (PER-16683)
apiUrlandpdp, including empty trailing delimiters, before creating SDK loggers or transports. Errors identify the option without retaining rejected values.PERMIT_API_URLandPERMIT_PDP_URLdefaults while preserving valid explicit overrides and explicit-undefined fallback.Safe errors and diagnostics (PER-16565)
PermitApiError, with useful HTTP status or transport codes and detached causes. Empty, text and validation responses produce readable descriptions.unknown, and the misleading generic error-body parameter is removed.User-list options (PER-12643; GitHub #83)
searchOperatorandincludeResourceInstanceRolesonusers.list. Operators arestartswith,endswithandcontains; explicit false is serialized and omitted options keep the API defaults.PaginatedResultUserReadenvelope, including nested resource-instance roles. Existing generated dispatch already supports the parameters; runtime files are unchanged by this unit.Tenant list totals (PER-11295)
includeTotalCount; true returns the completePaginatedResultTenantReadwith metadata and selected attribute types. Dynamic or optional flags retain the array/page union.Attribute result types (PER-16504; GitHub #82)
object; named interfaces, literal unions, readonly members and nullable inner values retain their declared shape.sync's{ user, created }envelope, getter aliases andwaitForSyncclones. Tenant membership returns the selected user attributes. Existing role-list parameter generics and flag inference remain unchanged.User invites (PER-12882)
permit.api.userInviteswith direct selected-environment list, create, get, full-body PATCH, delete and approve operations. Facts proxy settings do not reroute these calls or promise PDP synchronization or email delivery.Groups API (PER-16566)
permit.api.groupswith the eight approved GA operations: create, delete, direct list/get, user membership assignment/removal and resource-role assignment/removal.GroupReadresults from directGroupReadSchemaresults with internal IDs. Strict CJS/ESM consumers verify required bodies and precise inferred result types.Membership, detailed lists and PDP refresh (PER-16567)
tenants.addUser(tenantKeyOrId, userData)to create a new user in a tenant without requiring a role. An existing user remains a duplicate-user error.listDetailed()methods for role assignments, resource instances and relationship tuples. Preserve full nested envelopes, total counts, optional page counts, nulls and additive fields. Pagination defaults to page 1 and 100 rows; instance searches retain repeated query values.pdps.refresh({ reason })for the selected environment. Its response acknowledges submission, not completion. Individual-PDP refresh remains deferred.waitForSync, preserving selected context and repeated filters without promising PDP synchronization. Existing methods retain their routing.PDP discovery and request context (PER-16568)
getUserPermissions()config argument, preserving its filters and internal global-then-call context precedence.getAuthorizedUsers()with the complete resource, tenant and user-assignment envelope. The method follows the published container/cloud route contract; real-service validation uses the isolated container.getUserTenants()for role-derived tenant discovery. Preserve tenant metadata and documented defaults. An unavailable endpoint returns an actionable status-preserving error even when denial fallback is configured.filterObjects()using one bulk authorization request. Return original objects in order, preserving duplicates and extra application metadata; send only supported resource fields and apply each object's context over the call context. Empty input sends no request, while invalid/sparse positions and unsupported OPA mode reject before dispatch.check()retains direct OPA support.API and PDP coverage evidence (PER-16561)
pnpm verifyincludes the offline contract gate. A weekly/manual workflow checks only the two allowlisted public schema documents and retains bounded drift reports with GitHub failure notifications.Dependency security gates (PER-16559)
standard-versiontooling and its vulnerable dependency tree. Native version validation preserves semantic-version normalization, rerun and disabled-lifecycle safeguards; a release tag must match the committed package version.Tests and CI
pnpm testbuilds and runs unit/module-import tests without backend credentials.pnpm test:codegenchecks generator guard failures.Test execution and fixture integrity (PER-16569)
Grouped APIs and legacy removal (PER-16570)
api.getMethods(). Use the existing grouped clients; the migration guide lists every replacement and the changed argument/result shapes.conditionSets.list({ type })and unfiltered rule listing throughconditionSetRules.list(). Rule filters are independently optional, and pagination remains available.DeprecatedApiClient, the threeIDeprecated*interfaces,ContextTransform, and the deprecatedApiContext.levelalias.permittedAccessLevelremains the permission-level property. Public runtime and strict CJS/ESM tests reject removed names and compile every grouped replacement.ApiClientinherit the shared base directly, eliminating seven duplicate generated clients. Remove unused transform registration, dictionary/regex functions and internal method-bag code. Modern context, error, privacy and grouped-client checks remain.MIGRATION.mdin the tarball and regenerate the API reference. The new guide's OpenAPI inventory link resolves to a published repository copy for installed-package readers.Packed release evidence (PER-16571)
pnpm check:release-evidenceto bind supplied execution evidence to a clean SDK source tree, the exact packed candidate, the official npm 2.7.5 baseline and both installed consumer lockfiles. A fresh local build must reproduce the candidate archive byte for byte; version labels alone cannot establish identity.releaseReadyremains false.Migration guide and customer agent skill (PER-16572)
Versioned package and required gates (PER-16573; PER-16506)
ApiContextcompatibility across both entries.Generated JSON arrays and descriptions (PER-16682)
Arrayin the checked generator configuration.MonthlyUsage.monthly_tenantsnow matches Axios JSON responses instead of advertising JavaScriptSetmethods. Keep the captured UUID item schema, uniqueness constraint, default and source bytes intact.Checkout hook isolation (PER-16685)
Public API reference (PER-13613)
Reference website workflow (PER-13616)
SDK required checksfrom passing.main:/docspublisher to Actions, protecting the Pages environment, approving deployment and checking the hosted source marker. No Pages settings, workflow dispatch or website publication were performed for this change.Verification
ffe1cccc0a90dd7da47d2518e0c4483e30a3cf58, treea7c83831e25a04c55409cdc45f3ce4dcb8a37564; companion harness commitcb6733b6497447ae3e6833257caae1505ac0da7b, treef4deb0c15eec045bae858a07fb414757891d30e1. Two independent reviewers cleared the final Pages patch and the separate README-only harness correction.aa998c2e606955a097f93267d5bcd9bed187038d9607777271f341e8a5720727. It retains the prior strict TypeScript 6/7 CommonJS/ESM consumer checks, migration checks and all four dependency-security lanes on both support floors, with zero findings.Remaining validation
Groups commit
2a3330bhad two CI attempts stop at PDP readiness under PER-16553. Descendants02c0dbeanddd6204bpassed both runtime readiness, integration and e2e jobs, satisfying Groups acceptance. This successful run does not resolve the broader intermittent OPAL incident.ABAC decision assertions in the existing cloud e2e suite remain skipped under PER-16553; condition-set/rule/user CRUD still runs. This PR does not claim the OPAL incident is fixed.
CI may omit the two optional organization/project-scope tests when their scoped credentials are absent; the native report records each approved omission. The mandatory environment-key test must execute. All three execute in the owned local service run; CI job success alone is not presented as equivalent scope coverage.
Local harness evidence covers its implemented phase set; later SDK units will extend it. The local stack exercises real policy generation and decisions, but does not claim production event-bus or relay delivery coverage.
The release-gate implementation is complete locally; required-check settings and publication acceptance remain separate owner/dependency actions. Attribute generics (PER-16504) are implemented and locally validated in this PR. Tenant totals (PER-11295) are implemented and locally validated; user invites (PER-12882) are implemented and locally validated; public reference exports (PER-13613) are implemented and locally validated and the Pages workflow (PER-13616) is implemented and locally validated; owner-approved deployment and hosted verification remain separate actions. Generated model fixes (PER-16682) are implemented and locally validated; the primary-checkout hook-isolation fix (PER-16685) is validated and accepted. Base URL query/fragment rejection (PER-16683) is implemented and locally validated. The Node slice of bulk-result typing (PER-9298) remains blocked by incomplete response contracts. The tracker now includes these original units without counting covered aliases twice. Shared parity and Curtain Call remain external dependencies; local validation is not cross-SDK parity.
Credits
@Kyzgor contributed #122's native URL implementation and equivalence tests; the branch preserves that authorship. This PR also incorporates #131, #132 and #133.