Conversation
…ure is pending
New model: comp is pure plumbing. A dynamic check that doesn't succeed — a real
finding, a customer/transport error, or a thrown execution error — is held as
'inconclusive' ("pending", hidden from the customer) and handed to the self-heal
agent, which is the ONLY thing that decides our-bug (fix) vs real fail (show).
- decideRunStatus: dynamic + non-success → 'inconclusive'; no error-code logic.
- splitFailuresByDisposition: returns all-held (nothing decided on the comp side).
- The error-code classifier is now unreferenced (to be deleted in cleanup).
WIP: reveal-real-fail endpoint + the agent decision rewrite + spec updates still
to come. Not deployed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014PAsijjUQ1bMJuw8NuC1oR
…er-side / finding) The agent calls /reveal when it verdicts a held check as a GENUINE fail (the customer's creds/config are wrong, or a real compliance finding). Unlike /rerun (which applies the dynamic hold rule and may re-hold as 'inconclusive'), /reveal persists the TRUE status — success if it now passes, 'failed' with the real findings shown (failedCount > 0) otherwise — so the customer sees the red instead of a silent "pending". Mirrors rerunAndPersistCheck; never holds, never disables. tsc clean. Not deployed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014PAsijjUQ1bMJuw8NuC1oR
…decides everything
Per the design: comp must do ZERO judging of customer-vs-us. Removed every bit of
pre-classification so the only place that decides is the self-heal agent.
- Deleted check-failure-classifier.ts (the error-code customer/our_side/finding
judging) + its spec.
- Removed failureSignalsFromEvidence (HTTP-status/error-text extraction),
splitFailuresByDisposition, ClassifiableFailure, FailureDisposition from
task-check-evaluation.ts. decideRunStatus is now just:
success → success; dynamic non-success → 'inconclusive' (pending); else failed.
- Run paths (scheduled + manual) and rerun/reveal now record findings by identity
only ({connectionId, checkId, resourceId}); a dynamic failure is always held
pending for the agent. No signals, no patterns, no guessing.
- Rewrote the run-status spec for the new rule; deleted the split/signals specs.
my changed files compile; task-check-evaluation tests pass (19). Pre-existing
worktree spec failures (sync-gws / variables / credential-vault) are unrelated.
Not deployed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014PAsijjUQ1bMJuw8NuC1oR
…ne/JumpCloud device sync Devices imported from dynamic integrations now render correctly in the People tab instead of being mislabeled as failing agent devices. - agent-devices route + types: pass the real device source (agent/fleet/ integration) and the importing provider; drop integration rows that duplicate an agent serial - People > Devices table: Source column, source filter, "Not tracked" compliance for imported devices (no false-red checks), agent-only online status - Employee detail page, People compliance roll-up, compliance chart, CSV export, and people score: treat imported devices as inventory-only, not compliance-tracked, so they no longer skew compliance or suppress Fleet - tools/device-sync-definitions: version-controlled Intune + JumpCloud deviceSyncDefinition DSL, an offline mock test harness, and an apply script (the DSL otherwise lives only in the DB) Tests: devices suite, people-score helper, and 13 definition mock tests pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015iDU78gxNH9Wp9sex1BDLS
…finitions - lib/device-source.ts: shared sourceLabel + isComplianceTracked (used by the table and CSV so they can't drift); isComplianceTracked now treats Fleet as tracked — only integration imports are "Not tracked" - DeviceDetails: show live online/offline status only for agent devices - DeviceAgentDevicesList: keep the source filter visible while a non-default filter is active so users can't get stuck on an empty table - DeviceListCells: aria-label on the device-actions menu trigger - intune.mjs: fail loudly if pagination exceeds the page cap instead of importing a partial fleet as success - jumpcloud.mjs: stable sort on the systems + users pagination to avoid missing/duplicating records when data shifts mid-sync - test.mjs: make the harness await async tests so throw-cases are reliably caught and counted - devices-csv.test.ts: regression test proving an integration provider name can't reopen CSV formula injection (existing escaping already neutralizes it) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015iDU78gxNH9Wp9sex1BDLS
…eld error-runs keep task pending - P1: reveal/rerun now assert the taskId belongs to the SAME org as the connection before persisting a run (shared assertTaskBelongsToOrg helper), so a wrong/forged internal call can't contaminate another tenant's task history. - P2: count HELD runs (not held findings) toward heldCount — an error-only dynamic run (inconclusive, no findings) now keeps the task pending instead of letting it slip to 'done' while unresolved. Both run paths (scheduled + manual). my files: tsc clean; task-check-evaluation tests pass (19). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014PAsijjUQ1bMJuw8NuC1oR
New orgs are granted a single pentest credit at creation so the owner can
run their first penetration test without entering a card. Once that credit
is spent, running another pentest is an explicit, opt-in purchase — removing
the surprise auto-charges from the Stripe free-trial flow that were driving
refund requests.
- PentestCreditsService.grantInitialTrial(): idempotent per-org grant into
the billing-credits wallet (billing_credit_balances) — the store the
run-creation fallback reads — reusing the existing initialTrialAmount=1.
- POST /v1/pentest-credits/grant-initial (owner, pentest:create): thin,
idempotent endpoint the org-create flow calls.
- create-organization{,-minimal} call the grant after org activation,
mirroring the trust-portal bootstrap (non-fatal, covers both branches).
- No frontend change needed: getPentestAllowance already sums wallet
credits, so a credit>0 org sees "New Scan" and the run consumes the credit
via the existing tryConsumeCreditFallback path.
Re-introduces (now against billing_credit_balances) the free credit that was
removed in the Stripe-trial migration (f494299 -> f7e5e9f), deliberately
reversing that decision because the trial is what caused the refunds.
Tests: grantInitialTrial (grant args + stable idempotency key + no-op),
controller endpoint delegation, and the app helper (POST + non-fatal).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017JEEY9LtgmJRRFhLiSDogW
A revealed genuine fail persisted a 'failed' run but left the task green/pending — a false success signal. Now a reveal that resolves to 'failed' sets the linked task to 'failed' too (mirrors the run paths). A reveal that PASSES does not force 'done' (the task spans other checks; recomputed on the next scheduled run). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014PAsijjUQ1bMJuw8NuC1oR
…racked rendering - jumpcloud.mjs: only swallow a per-user 404 on the bindings call; rethrow auth/permission/5xx so a systemic failure can't report a "successful" sync with every device silently missing its owner - DeviceListCells: render the live-status dot only for agent devices (spacer otherwise, so imports aren't shown as offline agents); make the device name a focusable button so details are reachable by keyboard, not just mouse - DeviceDetails: suppress the Exception column for untracked checks - test.mjs: JumpCloud mock now honors skip/limit (real pagination contract); added multi-page pagination + binding 401-rethrow / 404-skip tests Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015iDU78gxNH9Wp9sex1BDLS
…ine limit Extract the shared mock harness into harness.mjs and the provider tests into intune.test.mjs / jumpcloud.test.mjs; test.mjs is now a thin runner. It imports the two suites sequentially via dynamic import because they use top-level await and stub the global fetch — static imports would interleave and clobber it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015iDU78gxNH9Wp9sex1BDLS
Address review (cubic P1): POST /v1/pentest-credits/grant-initial was guarded only by pentest:create, so any owner/admin/API-key holder on an EXISTING org could mint themselves a one-time free pentest credit (they lack the initial-pentest-trial:<orgId> idempotency key since existing orgs weren't backfilled). grantInitialTrial now reads organization.onboardingCompleted and only grants while the org is still in the creation/onboarding phase. onboardingCompleted defaults to false and only ever flips false->true (set by complete-onboarding), so established orgs are permanently ineligible and a pentest:create holder can no longer mint a credit for an existing org. Combined with the existing stable per-org idempotency key, issuance stays one-time per new org. Tests: added "already-onboarded org -> no grant" and "missing org -> no grant". Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017JEEY9LtgmJRRFhLiSDogW
…x, 429) Match the Intune retry coverage — assert a transient failure on the first systems fetch is retried and then succeeds. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015iDU78gxNH9Wp9sex1BDLS
Previously the reveal flipped any non-failed task to failed, which would resurrect a human-set not_relevant (dismissed) or in_review task. Restrict it to active workflow statuses (todo / in_progress / done) so a reveal never overrides a dismissed or under-review task. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014PAsijjUQ1bMJuw8NuC1oR
…mpcloud feat(devices): show integration-imported devices in People tab + Intune/JumpCloud device sync
…status formatting
## Problem
Multiple UI and data handling issues across ISMS documents:
- Back button returns to wrong tab (Company Forms instead of ISO 27001)
- Approver and owner fields display raw member IDs instead of names
- Party tags show internal identifiers instead of party names
- Status enums render unformatted in UI and exports (e.g. `on_track` instead of "On track")
- Organization and mission sections missing from editable view
- Editing interested parties triggers validation error on interestedPartyId
- Linked party ID field unnecessarily exposed to user
## Root cause
- IsmsDocumentShell back href missing tab query parameter
- RequirementsClient.toPayload sends interestedPartyId as null for existing rows; register validation rejects null
- Member/party name resolution missing in display layer (ApprovalDialog, ObjectiveEditor, IsmsSourceBadge)
- Enum status values not humanized in objectives template and PDF rendering
- ContextOfOrganizationClient omits org profile and mission section editors
- Interested parties edit drawer exposes internal linked party ID field
## Fix
- Preserve tab parameter in back navigation href
- Initialize interestedPartyId from existing row data before mutation
- Add member and party name lookups to approver, owner, and badge displays
- Map status enum to human labels in UI and export template
- Add organization and mission editors to context of organization view
- Hide linked party ID from edit interface (system-managed field)
## Explicitly NOT touched
- Register data structure or API contract
- Party and member lookup service implementations.
- Document approval workflow logic.
## Verification
✅ Back button from any ISMS document returns to ISO 27001 tab
✅ Approver selection dialog and approval display show member name
✅ Owner field in objectives shows member name
✅ Party tags resolve to party names
✅ Status field shows human-readable labels ("On track", "Not started", etc.)
✅ Status exports with human labels in PDF and DOCX
✅ Organization and mission sections visible and editable in main view
✅ Editing interested parties row preserves interestedPartyId and passes validation
✅ Linked party ID hidden from edit drawer
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
…c DB-only The Intune + JumpCloud deviceSyncDefinitions are authored and stored in the DynamicIntegration DB rows (via the internal dynamic-integrations endpoint), exactly like the employee syncDefinition and the checks. The in-repo source copies + apply script + tests duplicated that DB state and broke convention (a drift risk), so remove them. The live staging/prod definitions are unchanged and remain editable through the builder/internal endpoint. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015iDU78gxNH9Wp9sex1BDLS
chore(devices): remove tools/device-sync-definitions — keep device sync DB-only
Contributor
There was a problem hiding this comment.
5 issues found and verified against the latest diff
Confidence score: 2/5
apps/app/src/app/api/people/agent-devices/route.tsis missing a server-side RBAC check, so the endpoint could be called directly by any active-org session and expose device/integration-provider data despite page-level hiding. Add an API-level authorization guard before querying and returning data prior to merge.apps/app/src/app/(app)/[orgId]/people/devices/lib/devices-csv.tsmarks fleet devices as untracked, which can produce incorrect compliance status/check columns in exports and mislead downstream reporting. Switch to the sharedisComplianceTracked(d)helper and validate CSV output against the UI before merging.apps/app/src/app/(app)/[orgId]/people/devices/components/DeviceAgentDevicesList.tsxuses display labels as filter identifiers, so different sources with the same label can collapse into one option and hide valid filter choices. Use stable source/provider keys for option values and keep labels display-only.apps/app/src/app/(app)/[orgId]/people/devices/components/DeviceListCells.tsxandapps/app/src/app/(app)/[orgId]/people/devices/components/DeviceDetails.tsxduplicate presentation/tooltip logic, increasing drift risk in stale thresholds, check labels, and “Not tracked” copy between views. Extract shared constants/helpers to keep behavior consistent and reduce regression risk.
Tip: instead of fixing issues one by one fix them all with cubic
Re-trigger cubic
…-orgs feat(pentest): auto-grant one free pentest credit to new organizations
…issues fix(isms): resolve back nav, approver/owner display, party tags, and status formatting
…3308) - agent-devices + fleet-hosts routes: enforce RBAC with requireApiPermission (member:read, matching the People page) instead of a session-only check, so the device/integration data can't be read by an active-org session that lacks people access (P1) - CSV export: use the shared isComplianceTracked() so Fleet devices aren't wrongly marked "not_tracked"/"n/a" — keeps CSV consistent with the UI (P2) - DRY: move shared device presentation helpers (PLATFORM_LABELS, CHECK_FIELDS, formatTimeAgo, isDeviceOnline, stale + not-tracked copy) into device-source, and a shared NotTrackedBadge — used by both the list and details views (P3) - Source filter: key options by a stable source id (sourceKey) instead of the display label, so two providers sharing a name don't collapse into one (P3) Tests: devices suite + agent-devices route (81) green; typecheck clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015iDU78gxNH9Wp9sex1BDLS
fix(devices): address cubic review on device-import display (#3308)
CS-576 (re-open): customers could select an employee sync source in the
People tab but had no way to turn it back off. The only "off" levers were
disconnecting the integration (which also kills its compliance checks and is
labelled "remove all data") or an email-filter workaround — neither is a real
disable. The org-level `employeeSyncProvider` already supports null end-to-end
(`POST /employee-sync-provider {provider:null}` + `setSyncProvider(null)`), and
the daily 7 AM cron skips orgs whose provider is null — it was just never wired
to a UI control.
This adds a "Don't auto-sync" item to the sync-source dropdown that clears the
provider (stopping the scheduled sync) without disconnecting the integration or
touching already-imported people. Applies to every sync provider, not just
Entra. Selecting it routes to disable (never triggers a sync), and the hook now
confirms with a toast. Gated by `canManageMembers`; backend still enforces
`integration:update`.
Tests: cover setSyncProvider(null) disabling + provider selection.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M6zcF9bvPP1UwZgzK21cw1
Addresses cubic P2: the "Don't auto-sync" path called setSyncProvider(null) without any busy flag, so the dropdown stayed interactive during the request and a follow-up provider selection could race it to an inconsistent state. Add an isDisablingSync flag (mirroring isSyncing): set it around the disable request, include it in the Select's disabled guard, and bail out of the handler if a disable is already in flight. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M6zcF9bvPP1UwZgzK21cw1
…-sync-ui feat(people): add "Don't auto-sync" option to employee sync source
claudfuen
pushed a commit
that referenced
this pull request
Jun 30, 2026
# [3.94.0](v3.93.1...v3.94.0) (2026-06-30) ### Bug Fixes * **devices:** address cubic review on device-import display + sync definitions ([dda64db](dda64db)) * **devices:** address cubic review on the device-import display PR ([#3308](#3308)) ([9056d1b](9056d1b)) * **devices:** second cubic pass — JumpCloud error handling, a11y, untracked rendering ([ea93f29](ea93f29)) * **isms:** resolve back nav, approver/owner display, party tags, and status formatting ([c9a6697](c9a6697)) * **pentest:** gate initial free credit to new (un-onboarded) orgs only ([199e890](199e890)) * **people:** lock sync-source dropdown while disabling auto-sync ([541a72f](541a72f)) * **self-heal:** address cubic — validate task org on reveal/rerun + held error-runs keep task pending ([3cecc79](3cecc79)) * **self-heal:** reveal also syncs the task status (cubic P1) ([9bbf38b](9bbf38b)) * **self-heal:** reveal task-sync only flips ACTIVE statuses (cubic P2) ([5e3c6e3](5e3c6e3)) ### Features * **devices:** show integration-imported devices in People tab + Intune/JumpCloud device sync ([923a9e9](923a9e9)) * **pentest:** auto-grant one free pentest credit to new organizations ([a5f815f](a5f815f)) * **people:** add "Don't auto-sync" option to employee sync source ([ae88ec6](ae88ec6)) * **self-heal:** add /reveal endpoint — persist the real fail (customer-side / finding) ([e2f1fc0](e2f1fc0))
Contributor
|
🎉 This PR is included in version 3.94.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is an automated pull request to release the candidate branch into production, which will trigger a deployment.
It was created by the [Production PR] action.
Summary by cubic
Show integration-imported devices correctly across People, hold non‑success dynamic checks as pending until the self‑heal agent reveals genuine failures, auto‑grant one free pentest credit to new orgs so they can run a first test without a card, and let orgs turn off employee auto‑sync without disconnecting any integration.
New Features
people/agent-devicesnow returnssource(device_agent/fleet/integration) andintegrationProvider; drops imported rows that duplicate an agent serial.POST /integrations/connections/:connectionId/revealto persist a genuine fail (never held) and sync the task to failed when applicable.inconclusive(pending) with identity-only failing findings; the self-heal agent is the sole classifier.POST /v1/pentest-credits/grant-initialidempotently grants one free credit to new (onboarding) orgs; org-create flows call it. Prevents surprise trial charges.Bug Fixes
member:read) onpeople/agent-devicesandpeople/fleet-hostsroutes.not_trackedwithn/achecks; added Source column; use shared tracking logic so Fleet exports real checks; hardened against formula injection in provider names.interestedPartyIdin create/update.Written for commit 3a6d4aa. Summary will update on new commits.