Skip to content

feat(workflow): mount the remaining Work/workflow product surface - #512

Merged
cursor[bot] merged 17 commits into
codex/tracedecay-total-redesign-planfrom
cursor/mount-workflow-product-surface-2353
Aug 19, 2026
Merged

feat(workflow): mount the remaining Work/workflow product surface#512
cursor[bot] merged 17 commits into
codex/tracedecay-total-redesign-planfrom
cursor/mount-workflow-product-surface-2353

Conversation

@ScriptedAlchemy

@ScriptedAlchemy ScriptedAlchemy commented Aug 19, 2026

Copy link
Copy Markdown
Owner

Summary

Mounts the remaining Work/workflow product surface on codex/tracedecay-total-redesign-plan, closing audit items B3, B8, and A19 without recreating WorkflowStepExecutionService/execute_ready_step or the retired WorkProjection routes (1be58ce45). No version bumps.

B3 — catalog semantic admission gates workflow activation

  • New tracedecay_application::workflow_admission: every step operation must resolve to an available executable binding in the canonical Work executable catalog, and the definition's pinned_catalog_digest must name the live work_executable_catalog_digest() (the digest hashes every capability manifest and request/result schema authority, so the pin is the schema/capability compatibility check). Denials are typed (UnknownOperation, OperationUnavailable, CatalogPinMismatch).
  • WorkflowDefinitionService::admit_activation is the one authority both activation paths run: the service activate, and the daemon's journaled effect path (workflow_dispatch.rs), which previously journaled the CAS transition without even structural revalidation. validate_definition answers the same admission so preflight cannot diverge from activation.
  • Tests: activation refuses an unmounted operation and a foreign catalog pin before any lifecycle transition is journaled (workflow_coordination.rs), and the daemon journey registers an uncataloged candidate and asserts the mounted activate route refuses it as a typed invalid_request. Fixtures using the never-cataloged id operation.work.attempt_start are corrected to the mounted operation.work.start_attempt — exactly the drift the admission now catches.

B8 — dashboard workflow definition/run workspace

  • Workflow contracts (WorkflowDefinition, lifecycle requests, WorkflowDefinitionDisposition, WorkflowRunGetRequest, WorkflowRunProjection) join DashboardContractCatalogV1 and the generated Zod contracts; handoff and run-control requests are asserted not published (the browser never holds a bearer or mints fences/command ids).
  • New workflows workspace (channel 14): definitions list, decoded step tables with pinned digests, the three compare-and-swap lifecycle transitions (activate/retire/reject), and run projections off get_run — all through the same application envelope walker and /api/application/workflow/<segment> routes the catalog advertises, bound to the same operation ids. Refusals render the daemon's own typed state; the empty registry is drawn only when the daemon answered one.
  • DOM tests cover the decoded list/steps, refusal-vs-empty distinction, the CAS activation round trip, a lifecycle conflict rendered verbatim, run projections, and a concealed run.

A19 — Work-context integration/stack

Investigation outcome: nothing was removed from WorkOperation for integration/stack — apply/receipt/stack-freeze live in the Plan 36 native-integration family, and Plan 24 keeps accepted integration lowered only through that family, so no Work mutation op is added (the "advertised" ops exist only in stale dated mount lists in Plans 24/11c). What the Work workspace truthfully claims is the observed accounting: the dashboard's integration-outcomes and GitHub-stack-capability cards were typed absences with a stale "read model is not published" reason. They now decode the mounted operation.work.topology_metrics projection (work_merge_attempts_total kind × outcome cells; the github_stack_capability reading) through the existing application use case, cell by cell, with the projector's own typed absences and no summed or derived figures. The remaining undecoded dimensions keep truthful absence wording (unsupported, naming the event family). The decision is recorded in NEXT.md.

Codex review follow-ups (25d14190e)

  • Selected-project Workflow readsWorkflowOperation now declares is_read_only() (parity with the catalog effect class is pinned by a test), the project-scoped gateway admits exactly that read set by POST (SelectedProjectApplicationRead::Workflow), and answers it from the selected project's own canonical application router; lifecycle mutations stay refused under the read-only gateway exactly like Work commands.
  • Suppressed integration cells — the integration-outcomes headline now requires a readable cell: when the support floor suppresses every kind × outcome cell, the card wears the projector's typed reason and the wiped coverage envelope is never presented as a measurement; mixed readable/suppressed pages state both counts separately, with the headline coverage taken from a readable cell's envelope.
  • Catalog unavailability on activateCatalogAdmissionDenied(CatalogUnavailable) maps to Unavailable, not invalid_request.
  • Lifecycle control stateDefinitionDetail is keyed by the selected definition identity so the revision draft and last transition result reset when switching definitions.
  • No fabricated descriptor revision — the GitHub stack capability card states that the model-level reading carries no metric descriptor revision instead of inventing execution-topology-metrics.v1; the integration card reads the revision off a real cell only.

Verification

  • cargo check --workspace --all-features green on the merged tree (base merge 51b5623cd integrated).
  • tracedecay-application, tracedecay-dashboard-api, and tracedecay-rusqlite-runtime test suites green, including the new admission, contract-registration, gateway read-set, and effect-class parity tests. One pre-existing failure reproduces identically at the base commit a707c84f7 and is unrelated: doctor_findings_api::tests::findings_route_preserves_canonical_unknown_entries (environment-sensitive entry count, 11 vs 10 on this VM).
  • Dashboard: npm test 1693/1693, tsc --noEmit, production build, contracts:generate outputs committed, and contracts:check reports up to date.
  • Commit subjects pass commitlint.
  • Daemon journey (daemon_suite advanced_workflow_journey_test, run with the real 615 MB byte-pinned FastEmbed fixture on a tmpfs-backed profile): registration, the new catalog-admission denial, mounted activation, run start, fan-out, synthesis, and restart all pass; the run then stops at the direct semantic evaluator publication (semantic activation input was rejected), a host-sensitive stage this diff does not touch and that NEXT.md already tracks as remaining work for this journey (the earlier code graph database conflict blocker disappeared once PR fix(graph-db): bind supplied sealed manifests so first publish seats #510's fix was merged in). The B3 daemon-path assertion is upstream of that stage and passed.
Open in Web Open in Cursor 

cursoragent and others added 3 commits August 19, 2026 02:56
Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
@changeset-bot

changeset-bot Bot commented Aug 19, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 9bb9cc2

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

ScriptedAlchemy and others added 3 commits August 18, 2026 20:38
Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
…github.com/ScriptedAlchemy/tracedecay into cursor/mount-workflow-product-surface-2353

Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
@ScriptedAlchemy
ScriptedAlchemy marked this pull request as ready for review August 19, 2026 03:57

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 431e7cf168

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

callWork(
WORKFLOW_LIST_DEFINITIONS_ROUTE,
{},
scopedUrl(scope, WORKFLOW_LIST_DEFINITIONS_ROUTE.path),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Add Workflow reads to the project-scoped gateway

When the scope bar names any project, this rewrites the request to /api/projects/{id}/application/workflow/list-definitions, but selected_project_application_read in crates/tracedecay-dashboard-api/src/lib.rs recognizes only feedback and read-only Work operations. Non-active projects therefore reject the POST with 405, while an explicitly selected active project falls through to project_api_router, where the application Workflow routes are not mounted. Consequently definition listing—and the analogous get-run and lifecycle calls—cannot work in any project-selected scope; route Workflow reads through the selected project's application authority and restrict mutations according to scope writability.

AGENTS.md reference: AGENTS.md:L75-L77

Useful? React with 👍 / 👎.

Comment on lines +212 to +215
: {
available: true,
value: `${coverage.observed} observed native integrations across ${dimensionalCells.length} kind/outcome ${dimensionalCells.length === 1 ? 'cell' : 'cells'} — counts are the projector's own cells, never summed here`,
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep fully suppressed integration cells unavailable

When the Rust projector's support floor suppresses every dimensional integration cell, it retains those dimensions but sets each cell's value to null and publishes a typed support_floor_unmet absence. Because this branch checks only dimensionalCells.length, the card still reports an available “0 observed ... across N cells” headline and increments the page's measured count even though every displayed row is unavailable. Require at least one readable cell, or propagate the cells' typed absence, before marking the headline measured.

AGENTS.md reference: AGENTS.md:L95-L97

Useful? React with 👍 / 👎.

DaemonInvocationProblem::NotFoundOrNotAuthorized
}
tracedecay_application::WorkflowCoordinationError::InvalidDefinition
| tracedecay_application::WorkflowCoordinationError::CatalogAdmissionDenied(_)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Report catalog composition failures as unavailable

This arm also catches CatalogAdmissionDenied(CatalogUnavailable(_)), which the new admission code returns when the canonical executable registry or its digest cannot be composed. During activation that internal authority failure is consequently converted—and journaled by workflow_dispatch.rs—as a permanent caller-side invalid request, so retrying the request cannot recover when the catalog becomes available. Map the CatalogUnavailable subtype to DaemonInvocationProblem::Unavailable while retaining invalid-request handling for unknown operations and pin mismatches.

AGENTS.md reference: AGENTS.md:L147-L148

Useful? React with 👍 / 👎.

Comment on lines +77 to +79
{selectedDefinition === null ? null : (
<DefinitionDetail definition={selectedDefinition} />
)}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reset lifecycle state when switching definitions

If an operator selects definition A, submits or edits a revision, and then clicks definition B directly, React reuses the same DefinitionDetail/LifecycleControls instance because it occupies the same unkeyed position. The revision input and useMutation().data therefore remain from A: B can display A's disposition receipt and can be submitted with A's expected revision. Key this subtree by definition identity/version or explicitly reset both pieces of state when the definition changes.

AGENTS.md reference: AGENTS.md:L78-L83

Useful? React with 👍 / 👎.

Comment on lines +288 to +292
: metricsProvenance(
model,
model.github_stack_capability.coverage,
'execution-topology-metrics.v1',
'capability observations',

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Do not fabricate the capability descriptor revision

ExecutionGitHubStackCapabilityReadingV1 carries capability, fallback, coverage, and unavailability fields but no descriptor revision, yet every successful metrics response is reported here as pinned to execution-topology-metrics.v1. This presents provenance the wire authority never supplied and will silently retain the old pin if the backend's capability descriptor changes. Keep this facet typed-absent until the canonical response publishes a revision, or add that revision to the Rust-owned contract.

AGENTS.md reference: AGENTS.md:L95-L97

Useful? React with 👍 / 👎.

cursoragent and others added 11 commits August 19, 2026 05:11
Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
…rface-2353' into pr512

# Conflicts:
#	crates/tracedecay-application/src/workflow_admission.rs

Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
@cursor
cursor Bot force-pushed the cursor/mount-workflow-product-surface-2353 branch from 676a9d6 to 9bb9cc2 Compare August 19, 2026 13:53
@cursor
cursor Bot merged commit 3cfccec into codex/tracedecay-total-redesign-plan Aug 19, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants