Skip to content

Commit 152017c

Browse files
committed
Release 0.4.5 for Paperclip SDK 2026.517
1 parent fd0c4b0 commit 152017c

11 files changed

Lines changed: 645 additions & 54 deletions

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ For `0.4.x`, the boundary works like this:
126126
- `activity.logged` document events invalidate stale reconciled state so document-backed review blockers refresh promptly without a full browser-side merge layer
127127
- Focus exports the live Core snapshot, the reconciled/plugin-composed display snapshot, and bounded Core traces so replay/debug flows can inspect both the engine substrate and the final operator view
128128

129-
The plugin has been validated against [`@tomismeta/aperture-core@0.7.0`](https://www.npmjs.com/package/@tomismeta/aperture-core) and [`@paperclipai/plugin-sdk@2026.428.0`](https://www.npmjs.com/package/@paperclipai/plugin-sdk).
129+
The plugin requires Paperclip `2026.517.0` or newer and has been validated against [`@tomismeta/aperture-core@0.7.0`](https://www.npmjs.com/package/@tomismeta/aperture-core) and [`@paperclipai/plugin-sdk@2026.517.0`](https://www.npmjs.com/package/@paperclipai/plugin-sdk).
130130

131131
Approval overlay transport is opt-in until the Paperclip plugin SDK exposes a first-class approval client. Set the plugin config field `paperclipApiBase` when the worker can reach the host approval API; leave it empty to run Focus without approval overlays in hosted or restricted-network environments.
132132

docs/RELEASE-0.4.5.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# paperclip-aperture 0.4.5
2+
3+
`0.4.5` aligns Paperclip Aperture with the current Paperclip plugin SDK and
4+
uses the newer host attention contracts where they improve Focus judgment.
5+
6+
## Highlights
7+
8+
- upgraded `@paperclipai/plugin-sdk` from `2026.428.0` to `2026.517.0`
9+
- declares Paperclip `2026.517.0` as the minimum host version
10+
- surfaces Paperclip Blocked Inbox attention as first-class Focus evidence
11+
- surfaces active Paperclip recovery actions directly in Focus
12+
- keeps planning-mode blockers calmer unless the host marks them urgent
13+
- preserves document lock metadata in review handoff copy and diagnostics
14+
- excludes plugin-operation issues from host reconciliation scans
15+
16+
## Why This Matters
17+
18+
- lets Focus defer to Paperclip's own blocked-work and recovery signals instead
19+
of relying only on plugin-local heuristics
20+
- keeps Aperture current with the latest Paperclip issue, comment, and document
21+
contracts
22+
- improves operator clarity around locked review artifacts and planning-mode
23+
work without changing the plugin boundary
24+
25+
## Validation
26+
27+
- `pnpm verify`

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@tomismeta/paperclip-aperture",
3-
"version": "0.4.4",
3+
"version": "0.4.5",
44
"type": "module",
55
"private": false,
66
"description": "The live attention layer for Paperclip, combining Aperture Core continuity with Paperclip-native operator policy.",
@@ -54,7 +54,7 @@
5454
"access": "public"
5555
},
5656
"dependencies": {
57-
"@paperclipai/plugin-sdk": "2026.428.0",
57+
"@paperclipai/plugin-sdk": "2026.517.0",
5858
"@tomismeta/aperture-core": "0.7.0"
5959
},
6060
"devDependencies": {

pnpm-lock.yaml

Lines changed: 9 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

scripts/eval-issue-intelligence.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ function createIssue(input: CorpusFixture["issue"]): Issue {
4343
title: input.title,
4444
description: input.description,
4545
status: input.status,
46+
workMode: "standard",
4647
priority: "high",
4748
assigneeAgentId: null,
4849
assigneeUserId: null,

src/aperture/attention-context.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ export const ATTENTION_CONTEXT_IDS = {
1616
recommendedMove: "recommended-move",
1717
issueStatus: "issue-status",
1818
issuePriority: "issue-priority",
19+
issueWorkMode: "issue-work-mode",
20+
blockedReason: "blocked-reason",
21+
blockedSeverity: "blocked-severity",
22+
recoveryAction: "recovery-action",
23+
documentLock: "document-lock",
1924
latestComment: "latest-comment",
2025
agentStatus: "agent-status",
2126
pauseReason: "pause-reason",
@@ -78,6 +83,26 @@ export function issuePriorityItem(value: string): AttentionContextItem {
7883
return item(ATTENTION_CONTEXT_IDS.issuePriority, "Priority", value);
7984
}
8085

86+
export function issueWorkModeItem(value: string): AttentionContextItem {
87+
return item(ATTENTION_CONTEXT_IDS.issueWorkMode, "Mode", value);
88+
}
89+
90+
export function blockedReasonItem(value: string): AttentionContextItem {
91+
return item(ATTENTION_CONTEXT_IDS.blockedReason, "Blocked reason", value);
92+
}
93+
94+
export function blockedSeverityItem(value: string): AttentionContextItem {
95+
return item(ATTENTION_CONTEXT_IDS.blockedSeverity, "Severity", value);
96+
}
97+
98+
export function recoveryActionItem(value: string): AttentionContextItem {
99+
return item(ATTENTION_CONTEXT_IDS.recoveryAction, "Recovery", value);
100+
}
101+
102+
export function documentLockItem(value: string): AttentionContextItem {
103+
return item(ATTENTION_CONTEXT_IDS.documentLock, "Document lock", value);
104+
}
105+
81106
export function latestCommentItem(value: string): AttentionContextItem {
82107
return item(ATTENTION_CONTEXT_IDS.latestComment, "Latest comment", value);
83108
}

src/aperture/issue-intelligence.ts

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,12 @@ export type IssueActorDirectory = {
5151

5252
export type IssueDocumentSignal = {
5353
hasDocuments: boolean;
54+
hasLockedDocuments: boolean;
5455
latestDocumentTitle: string | null;
5556
latestDocumentUpdatedAt: string | null;
57+
latestDocumentLockedAt: string | null;
58+
latestDocumentLockOwnerKind: "agent" | "user" | null;
59+
latestDocumentLockOwnerId: string | null;
5660
resolvesArtifactRequest: boolean;
5761
};
5862

@@ -273,12 +277,18 @@ export function analyzeIssueDocuments(
273277
): IssueDocumentSignal {
274278
const latest = latestIssueDocument(documents);
275279
const latestUpdatedAt = toIsoString(latest?.updatedAt);
280+
const latestLockedAt = toIsoString(latest?.lockedAt);
276281
const commentUpdatedAt = comment?.updatedAt ?? null;
282+
const lockedDocuments = documents.filter((document) => !!document.lockedAt);
277283

278284
return {
279285
hasDocuments: documents.length > 0,
286+
hasLockedDocuments: lockedDocuments.length > 0,
280287
latestDocumentTitle: latest?.title ?? null,
281288
latestDocumentUpdatedAt: latestUpdatedAt,
289+
latestDocumentLockedAt: latestLockedAt,
290+
latestDocumentLockOwnerKind: latest?.lockedByAgentId ? "agent" : latest?.lockedByUserId ? "user" : null,
291+
latestDocumentLockOwnerId: latest?.lockedByAgentId ?? latest?.lockedByUserId ?? null,
282292
resolvesArtifactRequest:
283293
hasIntent(analysis, "share_with_board")
284294
&& !!latest
@@ -294,7 +304,9 @@ export function issueRecommendedMove(
294304
const normalized = analysis.text.replace(/\s+/g, " ").trim();
295305

296306
if (documentSignal?.resolvesArtifactRequest) {
297-
return "Monitor the review now that the memo is attached.";
307+
return documentSignal.latestDocumentLockedAt
308+
? "Monitor the locked review snapshot now that the memo is attached."
309+
: "Monitor the review now that the memo is attached.";
298310
}
299311

300312
if (hasIntent(analysis, "resolution")) {
@@ -338,7 +350,9 @@ export function issueHeadline(
338350
documentSignal?: IssueDocumentSignal,
339351
): string {
340352
if (documentSignal?.resolvesArtifactRequest) {
341-
return "The requested memo appears attached, so review should be able to continue.";
353+
return documentSignal.latestDocumentLockedAt
354+
? "The requested memo is attached and locked, so review should be able to continue from the preserved snapshot."
355+
: "The requested memo appears attached, so review should be able to continue.";
342356
}
343357

344358
if (hasIntent(analysis, "resolution")) {
@@ -386,9 +400,15 @@ export function issueWhyNow(
386400
if (documentSignal?.resolvesArtifactRequest) {
387401
return {
388402
whyNow: documentSignal.latestDocumentTitle
389-
? `${documentSignal.latestDocumentTitle} was attached after the request, so the missing artifact appears resolved.`
390-
: "A review document was attached after the request, so the missing artifact appears resolved.",
391-
factors: ["document attached", "review can proceed"],
403+
? documentSignal.latestDocumentLockedAt
404+
? `${documentSignal.latestDocumentTitle} was attached and locked after the request, so the missing artifact appears preserved for review.`
405+
: `${documentSignal.latestDocumentTitle} was attached after the request, so the missing artifact appears resolved.`
406+
: documentSignal.latestDocumentLockedAt
407+
? "A review document was attached and locked after the request, so the missing artifact appears preserved for review."
408+
: "A review document was attached after the request, so the missing artifact appears resolved.",
409+
factors: documentSignal.latestDocumentLockedAt
410+
? ["document attached", "document locked", "review can proceed"]
411+
: ["document attached", "review can proceed"],
392412
};
393413
}
394414

0 commit comments

Comments
 (0)