feat(adapters): PR-39 workspace-primitives adapters slice#99
Conversation
relayfile-adapters-owned slice of the PR-39 gap spec. Companion to relayfile#162 + cloud#697. Generated by a Ricky single-workflow run (26 steps, 0 failed) in an isolated worktree; verified green before commit. - Work Item B: removed the adapter-owned provider-specific digest() handler expectation from adapter docs + the digest/layout contract; contract check now asserts no per-provider handler is required. - Work Item C: by-edited/<date>/ alias emission wired into the per-provider path mappers (notion last_edited_time, linear updatedAt, github updated_at/merged_at/closed_at, jira/confluence updated) with layout-manifest support. - Work Item D: .schema.json / .create.example.json discovery source of truth verified beside every writable resource (73 endpoints). - Work Item E: provider LAYOUT.md content reflects real alias indexes + writeback resources; __-in-identifier sanitation covered. Verification: npm run test:digest-contracts (11+11 contracts) exit 0; npm run test:writeback-discovery (73 endpoints, 0 fail) exit 0; npm test (73/73 turbo tasks) exit 0. Intentionally excluded: - vitest.config.mjs IS included: it scopes root `npx vitest run` to the one real Vitest suite so the 231 node:test suites aren't mis-collected and spuriously failed. Honest infra, not a test quarantine — flagged for reviewer awareness. - by-edited/YYYY-MM-DD/_gate-target.ts: a workflow-declared-target placeholder; the real by-edited emission lives in the per-provider path mappers committed here. Unreferenced root dead code — left out. - scripts/generated-workflow-artifacts.test.mjs (asserts ricky's .workflow-artifacts scratch), workflows/generated/, .workflow-artifacts/, .trajectories/ trail churn. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (22)
📝 WalkthroughWalkthroughThis PR implements the Workspace Primitive Skills PR-39 adapters slice by eliminating adapter-owned digest handler contracts from documentation and verification scripts; adding "by-edited" date-indexed alias paths to five providers (Confluence, GitHub, Jira, Linear, Notion) via new path builders and reconciliation logic; expanding reserved writeback filename patterns; and systematically documenting editor scratch file ignores across all adapters while refining GitLab schemas. ChangesDigest Contract Refactoring
By-Edited Alias Implementation Across Providers
Writeback Discovery and Filename Ignore Patterns
🎯 3 (Moderate) | ⏱️ ~20 minutes
Possibly related PRs
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
|
There was a problem hiding this comment.
🔴 Linear planIssueDelete omits editedDate, leaking stale by-edited aliases on tombstone deletes
When a Linear issue is deleted via a tombstone, planIssueDelete reads the prior state (which now includes editedDate via extractPriorIssueState) but does not pass it through to issuePathsFor. The write path (planIssueWrite at packages/linear/src/emit-auxiliary-files.ts:310) and its reconciliation branch (line 341) both include editedDate, so updates correctly clean up stale by-edited aliases. However, the delete path at lines 375–383 individually lists every prior field except editedDate. This means issuePathsFor won't generate the linearIssueByEditedPath(...) entry, and the by-edited alias file will survive the delete as a ghost file. Compare with Jira (packages/jira/src/emit-auxiliary-files.ts:358: issuePathsFor({ id, ...(prior ?? {}) })) and Confluence (packages/confluence/src/emit-auxiliary-files.ts:271: pagePathsFor({ id, ...(prior ?? {}) })) which both use object spread and automatically include editedDate.
(Refers to lines 375-383)
Was this helpful? React with 👍 or 👎 to provide feedback.
| "position": { | ||
| "type": "object", | ||
| "description": "Optional GitLab position object for diff discussions.", | ||
| "additionalProperties": true | ||
| }, |
There was a problem hiding this comment.
🟡 GitLab issue note schema incorrectly includes position field meant only for MR discussions
The position field was added to the GitLab issue note comment schema (packages/gitlab/discovery/gitlab/projects/{projectPath}/issues/{issueIid}__{slug}/comments/.schema.json:13-16) and documented in .adapter.md line 59 as an optional field. However, the GitLab API's POST /projects/:id/issues/:iid/notes endpoint does not support a position parameter — that field is specific to merge request discussions (diff-level inline comments). With the schema now using additionalProperties: false, the position field will pass writeback validation, but when the adapter forwards it to GitLab's issue note API it will either be silently ignored or cause an error. The description text even says "Optional GitLab position object for diff discussions" which is self-contradictory on an issue note schema. The .adapter.md also mirrors this incorrect addition.
Prompt for agents
The position field was incorrectly added to the GitLab issue note schema. It should be removed from both the .schema.json file at packages/gitlab/discovery/gitlab/projects/{projectPath}/issues/{issueIid}__{slug}/comments/.schema.json (remove the position property from properties) and from the .adapter.md file at packages/gitlab/discovery/gitlab/.adapter.md (remove the position line from the issue note optional fields and fields list). The position field is correct in the merge request discussions schema and should remain there.
Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/linear/src/emit-auxiliary-files.ts (1)
377-385:⚠️ Potential issue | 🟠 Major | ⚡ Quick winInclude prior
editedDatein tombstone reconciliation paths.Delete planning reconstructs prior issue aliases but omits
editedDate, so previously emittedby-editedaliases are left stale after tombstones.Proposed fix
const paths = issuePathsFor({ id, identifier: prior?.identifier, title: prior?.title, stateName: prior?.stateName, assigneeId: prior?.assigneeId, creatorId: prior?.creatorId, priority: prior?.priority, + editedDate: prior?.editedDate, });🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/linear/src/emit-auxiliary-files.ts` around lines 377 - 385, The issuePathsFor call that builds tombstone reconciliation paths omits the prior issue's editedDate, leaving previously emitted by-edited aliases stale; update the object passed to issuePathsFor (the invocation assigning to paths) to include editedDate: prior?.editedDate so the tombstone/path generation considers the prior edited timestamp (reference symbols: issuePathsFor, prior, paths).
🧹 Nitpick comments (4)
scripts/verify-writeback-discovery.mjs (1)
58-60: ⚡ Quick winAvoid duplicate adapter-level failures by moving this check outside the endpoint loop.
This check is adapter-wide but runs once per endpoint, so one missing doc line can produce many duplicate failures.
Suggested diff
- if (!adapterMd.includes('*.tmp.json') || !adapterMd.includes('*.partial.json')) { - failures.push(`${adapter.slug}: .adapter.md must document ignored temporary/partial writeback filenames`); - } } + + if (!adapterMd.includes('*.tmp.json') || !adapterMd.includes('*.partial.json')) { + failures.push(`${adapter.slug}: .adapter.md must document ignored temporary/partial writeback filenames`); + } }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/verify-writeback-discovery.mjs` around lines 58 - 60, The adapter-level check that inspects adapterMd for '*.tmp.json' and '*.partial.json' is currently inside the endpoint loop and pushes failures per endpoint; move that check out of the endpoint loop so it runs once per adapter: locate the condition using adapterMd.includes('*.tmp.json') || adapterMd.includes('*.partial.json') and the failures.push(`${adapter.slug}: .adapter.md must document ignored temporary/partial writeback filenames`) and execute it once after adapterMd is loaded (or before iterating endpoints) rather than inside the loop that iterates endpoints, ensuring duplicates are not emitted.vitest.config.mjs (1)
18-18: ⚡ Quick winConsider removing
passWithNoTests: truefor more robust test discovery feedback.This config deliberately scopes Vitest to only the round-trip harness while other 231 tests run under Node's built-in runner. While
passWithNoTests: trueis intentional here to avoid failures when Vitest finds no matching tests, it masks potential breakage if the include glob ever fails. Verification confirms the current glob works (1 test file matched), but removing this flag would provide stronger signal if test discovery breaks in the future.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@vitest.config.mjs` at line 18, The config currently sets passWithNoTests: true which can mask broken test discovery; remove that option (or set passWithNoTests: false) from the Vitest configuration so the runner fails if the include glob finds no tests, and then verify the include glob used in the config still matches the intended round‑trip harness (run the vitest discovery locally/CI to confirm at least one file is matched); alternatively, if you need a safety net, comment the setting with a brief note linking it to the single harness so future changes reconsider it.packages/github/src/__tests__/emit-auxiliary-files.test.ts (1)
321-349: ⚡ Quick winAdd explicit by-edited assertions for issue alias emission.
The suite validates
by-editedfor PRs, but not for issues. Adding the issue-side assertion here will catch regressions in theissuesalias branch earlier.As per coding guidelines "Each path-mapper helper needs round-trip tests (compose -> parse -> equality); each alias subtree needs a collision test; each `LAYOUT.md` emitter needs a non-empty content test".Suggested test addition
assert.ok(writtenPaths.includes(githubByPriorityAliasPath('acme', 'widgets', 'issues', 'P0 Critical', 7))); + assert.ok(writtenPaths.includes(githubByEditedAliasPath('acme', 'widgets', 'issues', '2026-05-12', 7))); assert.ok(writtenPaths.includes(indexPath));🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/github/src/__tests__/emit-auxiliary-files.test.ts` around lines 321 - 349, Add an assertion to this issue test to verify the "by-edited" alias is emitted: when calling emitGitHubAuxiliaryFiles with the issue that has updated_at '2026-05-12T00:00:00Z', assert that client.writes includes the path produced by githubByEditedAliasPath('acme', 'widgets', 'issues', '<updated_at>', 7) (use the issue's updated_at value), mirroring the PR test pattern; update the test block around emitGitHubAuxiliaryFiles / writtenPaths to include this new assert so the issues alias branch is covered.packages/linear/src/__tests__/emit-auxiliary-files.test.ts (1)
326-336: ⚡ Quick winAdd a tombstone regression for
by-editedalias cleanup.Nice coverage for rename reconciliation. Please add one delete-path test where prior payload includes
updatedAtand assert the priorlinearIssueByEditedPath(...)is deleted on tombstone.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/linear/src/__tests__/emit-auxiliary-files.test.ts` around lines 326 - 336, Add a regression test that simulates a tombstone delete when the prior payload contains an updatedAt so the old by-edited alias is cleaned up: in the existing test use the prior payload with updatedAt set (e.g., date '2026-05-11'), call the tombstone/delete flow and then assert that deletedPaths includes linearIssueByEditedPath('2026-05-11', 'issue-123'); also keep the existing assertions that writtenPaths includes linearByTitleAliasPath(ISSUES_SCOPE, 'New Title', 'issue-123'), linearIssuePath('issue-123', 'AGE-8'), and linearIssueByEditedPath('2026-05-12', 'issue-123') to verify new aliases were created while the prior by-edited alias was removed (helpers to locate: linearIssueByEditedPath, linearByTitleAliasPath, linearIssuePath, and client.writes/deletedPaths).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/github/src/emit-auxiliary-files.ts`:
- Around line 472-473: The by-edited path is inconsistent: writes use
editedDateSegment(readLifecycleEditedAt(record)) but the index fallback/recovery
code derives dates from row.updated, causing mismatches and leftover by-edited
files; update the index-based delete/recovery logic to obtain the edited
timestamp via readLifecycleEditedAt(...) (the same source used when writing)
instead of using row.updated, and apply this change wherever similar logic
appears (refer to editedDateSegment, readLifecycleEditedAt, and the index
fallback/tombstone recovery blocks around the other occurrences).
In
`@packages/gitlab/discovery/gitlab/projects/`{projectPath}/issues/{issueIid}__{slug}/comments/.schema.json:
- Around line 13-17: Remove the unsupported "position" property from the
issue-note schema so POST /projects/:id/issues/:issue_iid/notes will no longer
accept diff discussion metadata; locate the JSON schema that defines "position"
(the "position" object entry) and delete that property (and any tests or schema
references that expect it) so validation matches the GitLab API for issue notes.
In `@packages/jira/src/__tests__/path-mapper.test.ts`:
- Around line 121-135: Add a unit that asserts the new alias subtree does not
collide with canonical or sibling alias namespaces: create a collision test
which composes a path with jiraIssueByEditedPath('2026-05-12', issueId) and then
assert it is different from the canonical/sibling paths (e.g.
jiraIssuePath(issueId) and any other alias composer like
jiraIssueByCreatedPath(date, issueId) if present) and/or that
extractJiraIdFromPathSegment applied to the leaf resolves only the intended id;
reference jiraIssueByEditedPath, extractJiraIdFromPathSegment and JIRA_PATH_ROOT
to locate the code under test.
In `@packages/jira/src/layout-prompt.ts`:
- Around line 50-57: The docs under "Writeback Discovery" list writable
discovery resources for jira/projects but the layout manifest
(packages/jira/src/layout.ts) lacks a corresponding writebackResources entry;
either add a writebackResources entry for "jira/projects" in the layout manifest
(update the writebackResources array/object in packages/jira/src/layout.ts to
include the projects resource with the proper schema/create example references)
or remove the "projects" bullet from packages/jira/src/layout-prompt.ts so the
documentation matches the manifest.
In `@packages/linear/src/layout-prompt.ts`:
- Line 10: Update the documentation line for the edited-date lookup
(`/linear/issues/by-edited/YYYY-MM-DD/<issue-uuid>.json`) to reflect the actual
timestamp precedence used at emission instead of claiming it's based only on
`updatedAt`; inspect the emitter code that writes the `/linear/issues/by-edited`
entries (search for the emit site or function that references that path) and
replace the sentence with an explicit ordered list of timestamps used as
fallbacks (e.g. which field is primary, then the secondary, etc.), state the
exact fields (e.g. `updatedAt`, `createdAt`, `closedAt` or whichever the code
uses) and note the date format (YYYY-MM-DD) for the bucket so consumers see the
real precedence and format.
In `@packages/notion/src/layout-prompt.ts`:
- Line 37: Update the by-edited alias examples in
packages/notion/src/layout-prompt.ts to use the dehyphenated UUID identifier
(idSuffix) that the system actually emits instead of the 8-character <short_id>
currently documented; locate the template strings or examples around the
by-edited alias (references in the file where the path shows
"by-edited/YYYY-MM-DD/<short_id>.json") and replace those example placeholders
with the dehyphenated UUID form (the idSuffix used when emitting filenames) so
agents are pointed to the real filenames.
In `@scripts/writeback-discovery-normalizer.test.mjs`:
- Around line 169-183: The test dereferences discussionEndpoint.resource and
commentEndpoint.resource without asserting the endpoints exist; add explicit
existence checks using assert.ok(discussionEndpoint) and
assert.ok(commentEndpoint) immediately after locating them via
normalized.endpoints.find(...) (before any access to .resource or
.resource.pathPatternSource) so a missing endpoint fails with a clear assertion
message rather than a TypeError.
---
Outside diff comments:
In `@packages/linear/src/emit-auxiliary-files.ts`:
- Around line 377-385: The issuePathsFor call that builds tombstone
reconciliation paths omits the prior issue's editedDate, leaving previously
emitted by-edited aliases stale; update the object passed to issuePathsFor (the
invocation assigning to paths) to include editedDate: prior?.editedDate so the
tombstone/path generation considers the prior edited timestamp (reference
symbols: issuePathsFor, prior, paths).
---
Nitpick comments:
In `@packages/github/src/__tests__/emit-auxiliary-files.test.ts`:
- Around line 321-349: Add an assertion to this issue test to verify the
"by-edited" alias is emitted: when calling emitGitHubAuxiliaryFiles with the
issue that has updated_at '2026-05-12T00:00:00Z', assert that client.writes
includes the path produced by githubByEditedAliasPath('acme', 'widgets',
'issues', '<updated_at>', 7) (use the issue's updated_at value), mirroring the
PR test pattern; update the test block around emitGitHubAuxiliaryFiles /
writtenPaths to include this new assert so the issues alias branch is covered.
In `@packages/linear/src/__tests__/emit-auxiliary-files.test.ts`:
- Around line 326-336: Add a regression test that simulates a tombstone delete
when the prior payload contains an updatedAt so the old by-edited alias is
cleaned up: in the existing test use the prior payload with updatedAt set (e.g.,
date '2026-05-11'), call the tombstone/delete flow and then assert that
deletedPaths includes linearIssueByEditedPath('2026-05-11', 'issue-123'); also
keep the existing assertions that writtenPaths includes
linearByTitleAliasPath(ISSUES_SCOPE, 'New Title', 'issue-123'),
linearIssuePath('issue-123', 'AGE-8'), and linearIssueByEditedPath('2026-05-12',
'issue-123') to verify new aliases were created while the prior by-edited alias
was removed (helpers to locate: linearIssueByEditedPath, linearByTitleAliasPath,
linearIssuePath, and client.writes/deletedPaths).
In `@scripts/verify-writeback-discovery.mjs`:
- Around line 58-60: The adapter-level check that inspects adapterMd for
'*.tmp.json' and '*.partial.json' is currently inside the endpoint loop and
pushes failures per endpoint; move that check out of the endpoint loop so it
runs once per adapter: locate the condition using
adapterMd.includes('*.tmp.json') || adapterMd.includes('*.partial.json') and the
failures.push(`${adapter.slug}: .adapter.md must document ignored
temporary/partial writeback filenames`) and execute it once after adapterMd is
loaded (or before iterating endpoints) rather than inside the loop that iterates
endpoints, ensuring duplicates are not emitted.
In `@vitest.config.mjs`:
- Line 18: The config currently sets passWithNoTests: true which can mask broken
test discovery; remove that option (or set passWithNoTests: false) from the
Vitest configuration so the runner fails if the include glob finds no tests, and
then verify the include glob used in the config still matches the intended
round‑trip harness (run the vitest discovery locally/CI to confirm at least one
file is matched); alternatively, if you need a safety net, comment the setting
with a brief note linking it to the single harness so future changes reconsider
it.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: eda99559-5862-4b33-a729-952690ecaa84
📒 Files selected for processing (86)
.claude/rules/relayfile-integration-digests.mdAGENTS.mddocs/digest-layout-contract.mddocs/workspace-primitives-pr39-adapters-spec.mdpackage.jsonpackages/asana/discovery/asana/.adapter.mdpackages/azure-blob/discovery/azure-blob/.adapter.mdpackages/box/discovery/box/.adapter.mdpackages/clickup/discovery/clickup/.adapter.mdpackages/confluence/discovery/confluence/.adapter.mdpackages/confluence/src/__tests__/emit-auxiliary-files.test.tspackages/confluence/src/__tests__/layout-prompt.test.tspackages/confluence/src/__tests__/path-mapper.test.tspackages/confluence/src/emit-auxiliary-files.tspackages/confluence/src/layout-prompt.tspackages/confluence/src/layout.test.tspackages/confluence/src/layout.tspackages/confluence/src/path-mapper.tspackages/core/fixtures/round-trip/github-pulls/expected.snapshot.jsonlpackages/core/src/runtime/file-native-router.test.tspackages/core/src/runtime/file-native-router.tspackages/dropbox/discovery/dropbox/.adapter.mdpackages/gcs/discovery/gcs/.adapter.mdpackages/github/discovery/github/.adapter.mdpackages/github/src/__tests__/emit-auxiliary-files.test.tspackages/github/src/__tests__/layout-prompt.test.tspackages/github/src/__tests__/path-mapper.test.tspackages/github/src/emit-auxiliary-files.tspackages/github/src/issues/issue-mapper.tspackages/github/src/layout-prompt.tspackages/github/src/layout.test.tspackages/github/src/layout.tspackages/github/src/path-mapper.tspackages/gitlab/discovery/gitlab/.adapter.mdpackages/gitlab/discovery/gitlab/projects/{projectPath}/issues/{issueIid}__{slug}/comments/.create.example.jsonpackages/gitlab/discovery/gitlab/projects/{projectPath}/issues/{issueIid}__{slug}/comments/.schema.jsonpackages/gitlab/discovery/gitlab/projects/{projectPath}/merge_requests/{mergeRequestIid}__{slug}/discussions/.create.example.jsonpackages/gitlab/discovery/gitlab/projects/{projectPath}/merge_requests/{mergeRequestIid}__{slug}/discussions/.schema.jsonpackages/gmail/discovery/gmail/.adapter.mdpackages/google-calendar/discovery/google-calendar/.adapter.mdpackages/google-drive/discovery/google-drive/.adapter.mdpackages/hubspot/discovery/hubspot/.adapter.mdpackages/intercom/discovery/intercom/.adapter.mdpackages/jira/discovery/jira/.adapter.mdpackages/jira/src/__tests__/emit-auxiliary-files.test.tspackages/jira/src/__tests__/layout-prompt.test.tspackages/jira/src/__tests__/path-mapper.test.tspackages/jira/src/emit-auxiliary-files.tspackages/jira/src/layout-prompt.tspackages/jira/src/layout.test.tspackages/jira/src/layout.tspackages/jira/src/path-mapper.tspackages/linear/discovery/linear/.adapter.mdpackages/linear/src/__tests__/emit-auxiliary-files.test.tspackages/linear/src/__tests__/layout-prompt.test.tspackages/linear/src/__tests__/path-mapper.test.tspackages/linear/src/emit-auxiliary-files.tspackages/linear/src/layout-prompt.tspackages/linear/src/layout.test.tspackages/linear/src/layout.tspackages/linear/src/path-mapper.tspackages/notion/discovery/notion/.adapter.mdpackages/notion/src/__tests__/emit-auxiliary-files.test.tspackages/notion/src/__tests__/layout-prompt.test.tspackages/notion/src/__tests__/path-mapper.test.tspackages/notion/src/emit-auxiliary-files.tspackages/notion/src/layout-prompt.tspackages/notion/src/layout.test.tspackages/notion/src/layout.tspackages/notion/src/path-mapper.tspackages/onedrive/discovery/onedrive/.adapter.mdpackages/pipedrive/discovery/pipedrive/.adapter.mdpackages/postgres/discovery/postgres/.adapter.mdpackages/redis/discovery/redis/.adapter.mdpackages/s3/discovery/s3/.adapter.mdpackages/salesforce/discovery/salesforce/.adapter.mdpackages/sharepoint/discovery/sharepoint/.adapter.mdpackages/slack/discovery/slack/.adapter.mdpackages/teams/discovery/teams/.adapter.mdpackages/zendesk/discovery/zendesk/.adapter.mdscripts/digest-layout-contracts.mjsscripts/generate-writeback-discovery.mjsscripts/verify-writeback-discovery.mjsscripts/writeback-discovery-normalizer.mjsscripts/writeback-discovery-normalizer.test.mjsvitest.config.mjs
There was a problem hiding this comment.
7 issues found across 86 files
Tip: instead of fixing issues one by one fix them all with cubic
Partial review: This PR has more than 50 files, so cubic reviewed the highest-priority files first. During the trial, paid plans get a higher file limit.
You can try an ultrareview to bypass the file limit, comment @cubic-dev-ai ultrareview. Learn more.
Re-trigger cubic
Summary
The relayfile-adapters-owned slice of the PR-39 workspace-primitives gap spec. Companion to relayfile#162 (relayfile slice) and AgentWorkforce/cloud#697 (cloud slice). Generated by a Ricky single-workflow run (26 steps, 0 failed) in an isolated worktree off
origin/main; verified green before commit.Delivered
digest()handler expectation from adapter docs + the digest/layout contract; the contract check now asserts no per-provider handler is required (generic-over-events rendering, per the canonicalized Work Item A decision).by-edited/<date>/alias emission wired into the per-provider path mappers (notionlast_edited_time, linearupdatedAt, githubupdated_at/merged_at/closed_at, jira/confluenceupdated), with layout-manifest support..schema.json/.create.example.jsondiscovery is the adapter source of truth beside every writable resource.LAYOUT.mdcontent reflects real alias indexes + writeback resources;__-in-identifier sanitation covered.Verification
npm run test:digest-contracts→ 11 category + 11 regression contracts, "adapter metadata/layout contracts do not require provider digest handlers" — exit 0npm run test:writeback-discovery→ 73 writeback discovery endpoints, 0 fail — exit 0npm test→ 73/73 turbo tasks successful (e.g. github adapter 249 tests / 0 fail) — exit 0Reviewer notes — included/excluded decisions
vitest.config.mjsis included (flagged): unlike cloud#697's quarantine, this is honest infra — the adapters repo's 231 suites arenode --test, and a bare rootnpx vitest runwould walk up to a workspace config and spuriously fail all of them ("No test suite found"). This scopes vitest to the one real Vitest suite (core round-trip) withpassWithNoTests. It does not exclude any failing test. Calling it out because any new root test config deserves a look.by-edited/YYYY-MM-DD/_gate-target.ts: a workflow-declared-target placeholder. The realby-editedemission lives in the per-provider path mappers committed here; that file is unreferenced root dead code.scripts/generated-workflow-artifacts.test.mjs(asserts ricky's.workflow-artifacts/scratch),workflows/generated/,.workflow-artifacts/,.trajectories/trail churn.Scope
Adapters slice only. relayfile#162 + cloud#697 are the companion slices; this completes the 3-repo PR-39 plan.
🤖 Generated with Claude Code