fix(agent): ground replies in tool receipts and repair delegation delivery - #496
Merged
Conversation
…gainst runtime union
…pe, run-dir lifecycle
…ropy net, replace source-greps
PR description incompletePlease fill in all required sections before this PR can be reviewed. Required sections: Description, Related Issue, Type of Change, Checklist, RED Test Proof. For code changes in See CONTRIBUTING.md for the full contribution bar. |
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
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.
Intent
Ship the completed local real-user Telegram campaign changes: preserve Comis as a generic domain-neutral runtime, include every test-first product, observability, harness, and documentation fix produced by the campaign, retain strict security and no-backward-compatibility contracts, and publish the committed feature branch as a pull request. The campaign itself remains honestly PARTIAL because safety-suspended and stopped-before-drive corpus rows were not claimed as passes, while all encountered COMIS failures were fixed and validated. Push the branch, create the PR, and require the configured review, test, documentation, lint, and CI gates; do not weaken checks or discard pipeline-generated fixes.
What Changed
packages/agent/src/executor/response-grounding.tsgains guards for outbound audio/image/delivery-status claims (a backgrounded spawn or a runtime voice route is distinguished from a synthesis receipt), andenforceRuntimeSelfReportEvidencenow rejects unsupported cost/duration/outage-receipt answers using newobservabilityEvidenceLimits(cost: runtime_estimate,providerInvoice: unverified,crossExecutionDurationRanking: unavailable) instead of only checking that anobs_querycall happened. Prompt-skill routing (prompt-skill-request-routing.ts,request-tool-nudge.ts) no longer arms off recalled history, backgrounded completions, extracted content, or generic stopwords; citation evidence prefers the current turn's receipts; degraded/input-guard replies pick up i18n coverage; and recall (rag/relevance-scorer.ts,memory-recall.ts) keeps space-free prose searchable while blocking opaque-payload inheritance.packages/daemon/src/api/graph-handlers/graph-dispatch-hint.tsreturns a per-route dispatch hint that only promises notification when an announcement route and durable delivery exist; graph completion routes retain scoped caller turn/session identity;IncidentGraphRungains requiredannouncementDelivery(not-requested/unavailable/committed/retained/failed) plus optionalsessionKey; andobs.explainpicks up arequest.clarification_requiredtrajectory event,recallDisposition,route_validation_failedskip reason, and reworked completion-evidence/tool-invocation verdicts. Config posture adds anexecSandboxDisabledsignal forskills.execSandbox.enabled: "never".setup-channels/attachment-delivery-hooks.tspublishes every successfulChannelPort.sendAttachmentthroughafter_deliveryhooks (with delivery authority and adependencywarn on hook failure); bare-link parsing keeps IPv6 hosts intact; the secret entropy backstop swaps its delimiter check for a structure check so source expressions are excluded while password punctuation stays covered;web_searchnames the exact missing provider secret/knob; the skill manifest addscomis.min-distinct-web-fetch-urls/comis.min-distinct-web-search-querieswith defensive parsing that ignores malformed values instead of hiding the skill. Live Telegram/self-driving harness scripts and 20 docs files (json-rpc, channel delivery, skills manifest, environment variables, CLI) are updated to match.Risk Assessment
Testing
I ran every changed test file in the change set across all five tiers it touches — the 68 changed package unit files (4350 tests), the changed architecture and contracts tests, the self-driving live-kit project, the credential-free Stage-B legs of the six changed live Telegram/Signal scenarios, and the new real-daemon config-posture integration test — plus the intent-named generic-runtime-boundary gate, the regenerated web-contract drift/size/parity gates, and the bundled deep-research skill mirror gates; everything passes, and the only skips are the COMIS_LIVE Stage-C legs that need real Telegram and model credentials this environment does not have (consistent with the intent's own "honestly PARTIAL" statement). Beyond green tests I produced three product-level artifacts: a run of the daemon's real attachment-delivery + mirror wiring showing the emulator's
sendPhoto/sendVoicewire record next to the two persisteddelivery_mirrorrows with distinct idempotency hashes and a failed send that records nothing; a transcript of the exact chat copy a user receives when an image/voice/delivery-status/delegation claim lacks a receipt versus when the receipt exists; and a realcomis explain --graph --offlineCLI transcript renderingnotification=retained/notification=unavailableand the graph→caller session join, read back from a record written by the product's ownwriteRunMetadata. No screenshots apply: the change has no rendered UI surface — the web-facing part is generated API contract JSON/TS, and the user-visible surfaces are chat text and CLI output, both captured as transcripts. I created no files in the worktree (git statusandgit clean -nxdare clean apart from pre-existing gitignored build output); all evidence lives in the dedicated evidence directory.Evidence: Outbound Telegram attachment: what the chat received and what the runtime persisted
AGENT SENDS two captionless attachments to Telegram chat 424242 adapter results : ok, ok CHANNEL ORACLE — what the Telegram user received (recorded by the emulator): sendPhoto mediaKind=photo caption="" sendVoice mediaKind=voice caption="" MIRROR ORACLE — what the runtime persisted in delivery_mirror (real product schema): origin=channel:attachment channel=telegram/424242 status=pending text="" media_urls=[".../screenshot.png"] idempotency_key=cv_1FsgHETFOjN85Cor7SVtgwzEI9ThBfK4i2zmJnQsmiY:a84882638a615cd3:1786516124 origin=channel:attachment channel=telegram/424242 status=pending text="" media_urls=[".../briefing.ogg"] idempotency_key=cv_1FsgHETFOjN85Cor7SVtgwzEI9ThBfK4i2zmJnQsmiY:363ce1d2c1ec59c6:1786516124 distinct idempotency hashes for the two captionless files: 2 of 2 FAILED SEND — the emulator rejects sendPhoto; the mirror must claim nothing: adapter result : error (send refused by Telegram) delivery_mirror row count: 2 (unchanged — no phantom delivery recorded)Evidence: Reply-honesty transcript: the chat copy a user receives with and without a receipt
── image claim, NO generation or attach receipt user sent : Can you create a picture of the office layout and send it here? model drafted : I created the picture and sent it to you. user receives : I could not verify creation or delivery of the requested image in this turn because there is no successful current-turn generation or trusted completion receipt. I cannot confirm that it was created or delivered; please retry. replaced : true (missing_outbound_image_evidence) ── image claim, WITH a successful message.attach receipt — kept verbatim user receives : I created the picture and sent it to you. replaced : false ── voice-note claim, NO tts receipt and NO configured voice route user sent : can you please reply with a voice message? model drafted : Done — the voice message is sent. user receives : I could not verify delivery of the requested audio in this turn because there is no successful current-turn synthesis or trusted completion receipt. I cannot confirm that it was delivered; please check for a voice message or retry. replaced : true (missing_outbound_audio_evidence) ── delivery-status follow-up, NO current delivery/observability receipt user sent : did it send? model drafted : Yes, it was sent successfully. user receives : I could not verify whether the prior outbound item was delivered in this turn because there is no current delivery or observability receipt. I cannot confirm delivery yet. replaced : true (missing_outbound_delivery_status_evidence) ── answer after a SUCCESSFUL spawn whose delegated result is not disclosed model drafted : Today is 11 August 2026. user receives : I successfully started the requested sub-agent. Its result has not been verified in this turn yet. replaced : true (successful_spawn_response_ungrounded)Evidence: `comis explain --graph --offline` — graph notification disposition + caller-session join
Session: acme:telegram:chat-4471 Outcome: ok (endReason=unknown — rollup unresolved (no session-end record found), degraded=false) Graph: completed · graph-nightly-digest-1 · 2/2 succeeded · 0 failed · 0 skipped · notification=retained gather: completed · 0ms · attempts=1 · run=run-gather summarize: completed · 0ms · attempts=1 · run=run-summarize Session: acme:telegram:chat-4471 Graph: completed · graph-durability-off-2 · 2/2 succeeded · 0 failed · 0 skipped · notification=unavailableEvidence: Stage-B live Telegram delivery + attachment-mirror scenario run
Evidence: Changed-package unit test run (68 files, 4350 tests)
Evidence: Real-daemon config-posture integration run (obs.system.health surfaces exec-sandbox relaxation)
Evidence: Evidence harnesses used for the manual verification runs
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
packages/agent/src/executor/prompt-skill-request-routing.ts:142- Prompt-skill routing was broadened from nano-only to every capability class (executor-tool-assembly.ts:690 removed thecapabilityClass !== "nano"gate), and the shippeddeep-researchskill now declaresmin-distinct-web-fetch-urls: 3/min-distinct-web-search-queries: 3. Routing still admits a skill on only 2 shared content terms (prompt-skill-request-routing.ts:142, MIN_SHARED_TERMS=2) against deep-research's new ~65-content-term "MANDATORY…" description (explain, understand, research, information, current, online, source, answer, memory, search, reports, documentation, …). Once routed on a read-shaped turn,runRequestToolNudgearms the floor (request-tool-nudge.ts:535-539), runs up to 4 extra bounded continuations, and on failure returnsrecovered:false, whichpromoteToolInvocationStall(executor-post-execution.ts:934) turns intotool_invocation_stall— executor-post-execution.ts:2377 then REPLACES the model's answer with a deterministic "could not verify" reply and the rollup records degraded:true. Concrete path: user asks "explain the deployment reports we generated" on an agent with web_search/web_fetch available → 2+ shared terms route deep-research → floor armed → the model answers correctly from local context, or fetches only 2 distinct URLs because the third 404s → the correct answer is discarded. The docs acknowledge the design (docs/skills/manifest.mdx), but the combination of a 2-term routing bar, the new all-capability-class routing, and an answer-destroying completion gate on the default shipped skill is a product decision worth explicit sign-off — e.g. raising MIN_SHARED_TERMS for gate-bearing skills, or degrading an unmet floor to an appended sourcing caveat instead of discarding the reply.packages/core/src/security/secret-detection.ts:145- The entropy backstop gate changed from a delimiter denylist/[\s:\/?&=@,]/to an allowlistCREDENTIAL_BODY_RE = /^[A-Za-z0-9_.+-]+$/, solooksLikeSecretValuenow short-circuits to false for any value containing characters outside[A-Za-z0-9_.+-]. The false positive this fixed — the added corpus lineconst name = document.getElementById('runName').value.trim();— is scrubbed per whitespace-delimited token (NON_WHITESPACE_TOKEN_RE = /\S+/gin secret-egress-guard.ts), and the offending token is excluded by(,),'under either regex, so the new allowlist is far stricter than the fix required. Failure scenario: a bare 44+ char high-entropy credential containing ordinary password punctuation not present in the old set — e.g. a Django-style SECRET_KEY drawn froma-z0-9!#$%^*(-_=+)that happens to contain no@,&,=,:,/,?, or,(~13% of 50-char keys) — was previously redacted by the entropy backstop and now passesscrubSecretsFromTextunredacted into agent output, memory writes, and graph announcements. The labelled-assignment paths still coverpassword=…shapes, so this is the last-resort net only. This also bears on the intent's REQUIRED criterion "retain strict security and no-backward-compatibility contracts … do not weaken checks". A narrower exclusion (keeping the old delimiters and adding only source-expression characters such as()[]{}'") would fix the reported false positive without shrinking the net.packages/agent/src/executor/executor-post-execution.ts:1758-enforceRuntimeSelfReportEvidencenow returns three reasons, but theexecution:recovery_attemptedemit only branches onunsupportedOutageReceipt. A correction with reasonunsupported_runtime_self_report_evidence(the receipt existed but could not support a comparative-latency or provider-billed-cost claim) is published on the event bus asmissing_runtime_self_report_evidence— the opposite claim, since a successful obs_query receipt did exist.events-messaging.tsaddedunsupported_outage_receipt_evidenceto the reason union but not this third value. Failure scenario: a user asks "why was the slowest execution slow?", obs_query succeeds withcrossExecutionDurationRanking: "unavailable", the guard replaces the answer with the unsupported-evidence reply, andcomis explain/ the trajectory report "lacked a successful current-turn obs_query receipt" — sending the operator to check obs_query admission for a turn where obs_query worked fine. The precise reason survives only in the audit-event metadata.packages/agent/src/executor/executor-post-execution.test.ts:1197- Three newly added tests ("source-grep — outbound audio completion requires current delivery evidence", "— outbound image completion…", "— elliptical delivery status…") readexecutor-post-execution.tsas text and assert regex matches on function names (enforceOutboundAudioEvidence\(), string literals (response.outbound_audio_evidence_guard), array-literal shapes (acceptedEvidence: [ "tts_synthesize", … ]), andindexOfcall ordering. Existing runtime-self-report and citation source-greps also gained new source-content lines. This is the flagged anti-pattern: a behavior-preserving refactor (renaming the local, extracting the emit, reordering an object literal) breaks these while the behavior is intact, and a commented-out or dead call site would satisfy them. The guards themselves already have real behavior probes in executor-response-filter.test.ts and degraded-reply.test.ts; what the source-greps uniquely claim — that postExecution actually invokes each guard, emits the audit/recovery events, and does so beforesynchronizeFinalAssistantResponse— is directly observable by drivingpostExecutionwith a stub eventBus and asserting the emitted events and finalresult.response. Replace these three with that probe rather than extending the grep suite; no repo-wide cleanup of the ~28 pre-existing source-greps is being requested.packages/agent/src/executor/response-grounding.ts:527-enforceOutboundAudioEvidencefully short-circuits whenruntimeAudioDelivery === true, which orchestrator/execution-execute.ts:206-215 computes by pre-runningautoVoiceDeliveryActive— the auto-TTS decision, not the delivery outcome.executeVoiceResponsedeliberately returnsok({ voiceSent: false })on every synthesis/conversion error so text delivery can proceed. Failure scenario: user says "say that out loud", the voice route is configured so the guard passes an "I've recorded that for you" reply unchecked, then TTS synthesis or the ffmpeg conversion fails and the pipeline falls back to text — the user receives a text message asserting audio was sent, which is exactly the claim this guard exists to prevent. Not a regression (the guard is new on this branch) and the prediction matchesexecuteVoiceResponse's ownhasMediaUrl: falseinput, so the hole is bounded to delivery-time failures; closing it would mean re-checking the claim after the voice pipeline settles rather than before execution returns.packages/agent/src/executor/citation-evidence.ts:370-citationEvidenceDigestsForTurnchanges the allowed-digest set from the unioncurrent ∪ relayed ∪ historicaltofresh.length > 0 ? fresh : historical, so durable receipts from earlier turns in the same session are excluded the moment this turn produces any fresh fetch or relayed digest. Failure scenario: a follow-up where the assistant fetches one new source and legitimately re-cites two URLs it fetched (and journalled) two turns earlier —enforceCitationEvidencenow strips those two prior citations from the reply even though durable receipts back them, degrading a correct sourced answer. The comment states this is intentional ("durable receipts fill only an evidence-free follow-up"), and the shipped deep-research procedure now instructs re-fetching every candidate citation, which mitigates it in the routed case; flagging so the tradeoff is a conscious one for non-deep-research turns.packages/daemon/src/wiring/setup-delivery.ts:663- The delivery-mirrorafter_deliveryhook's missing-authority branch was demoted fromlogger.warnwitherrorKind: "precondition"and an actionable hint tologger.debug. The demotion is justified for the neworigin: "channel:attachment"path (attachments delivered outside a resolved turn are routine and correctly skipped), but it also silences the pre-existing text-delivery case: if a regression breaksctx.deliveryAuthority/ctx.destinationEndpointbinding for ordinary replies, mirroring silently stops and the agent loses its own-utterance continuity across restarts with no evidence at the default log level. This runs against the CLAUDE.md rule that diagnosability must not depend onlogLevel: debughaving been set before the incident. Consider branching onevent.origin— DEBUG forchannel:attachment, WARN for a turn-bound text delivery.🔧 Fix: narrow evidence-floor arming, restore secret entropy net, replace source-greps
6 issues (4 warnings, 2 infos) still open:
packages/agent/src/executor/prompt-skill-request-routing.ts:198- The fix raises floor-arming from 2 to 3 shared terms, but the answer-discarding path is still reachable on ordinary local-context prose. Verified against the SHIPPED skills/deep-research/SKILL.md description (63 content terms after tokenize()/ROUTING_STOPWORDS, including explain, information, reports, documentation, source, answer, memory, search, current, online, topic, short, paragraph, skill, load, instead): "explain what information those reports actually contain" scores exactly 3 (explain, information, reports) and "search my memory for the current status" scores 3 (search, memory, current). Both arm min-distinct-web-fetch-urls:3 + min-distinct-web-search-queries:3. Neither is a conversation-history lookup, so CONVERSATION_HISTORY_RECALL_PATTERN (line 143) does not exclude them. Once armed, runRequestToolNudge (request-tool-nudge.ts:447) sets webEvidenceGateActive, returns recovered:false when the receipts never arrive, promoteToolInvocationStall raises tool_invocation_stall, and executor-post-execution replaces the model's correct answer with the deterministic "could not verify" reply while the rollup records degraded:true. The fix round's own new docs guidance (docs/skills/manifest.mdx:144, "Write a narrow, distinctivedescriptionon any skill that declares a floor") is contradicted by the only shipped skill that declares floors — its description is deliberately broad ("MANDATORY: … any request to understand or explain a topic …"). A threshold bump against a 63-term generic description does not establish the invariant; the durable boundary is either (a) narrowing the shipped description to distinctive terms, or (b) degrading an unmet floor to an appended sourcing caveat instead of discarding the reply. Both change product behavior, so this needs the author's call rather than another threshold tweak.packages/agent/src/executor/executor-post-execution.ts:1760- The fix round added theunsupportedEvidence ? "unsupported_runtime_self_report_evidence" : …branch to theexecution:recovery_attemptedemit, but nothing fails if that branch is wrong. response-grounding.test.ts:228/289 only proves the guard RETURNS that reason; events-messaging.test.ts:33 only proves the bus type carries the string; and the source-grep at executor-post-execution.test.ts:1223 uses lazy[\s\S]*?between "unsupported_outage_receipt_evidence" and "missing_runtime_self_report_evidence", so it matched before the fix and still matches with the new branch deleted. The mapping the fix exists to correct — guard reason -> emitted event reason inside postExecution — has no assertion. The harness the same commit added (pi-executor.test.tsrecoveryReasons(deps)) can assert it directly: drive execute() with an obs_query result carryingobservabilityEvidenceLimits.crossExecutionDurationRanking: "unavailable"on a "why was the slowest execution slow" request and assert the emitted reason isunsupported_runtime_self_report_evidence, notmissing_runtime_self_report_evidence.packages/agent/src/executor/executor-post-execution.test.ts:1222- The fix round removed the three new source-grep tests but left the source-content-only assertions this branch ADDED to two existing greps: line 1222expect(stripped).toMatch(/unsupported_outage_receipt_evidence/)and lines 1223-1225's emit-shape regex, plus line 1145expect(stripped).toMatch(/citationEvidenceDigestsForTurn\(\{/). Each asserts only that a literal or a call spelling appears in executor-post-execution.ts text: renaming the local, hoisting the emit into a helper, or commenting the call out satisfies or breaks them independently of behavior — and as noted above, line 1223's lazy regex already matched the pre-fix source. Per the test-quality rule these newly added assertions should be removed or refined; thepi-executor.test.tsprobe pattern the same commit introduced (assertresult.response+recoveryReasons/auditActionTypesfrom a drivenexecute()) is the semantic replacement. No cleanup of the ~28 pre-existing greps is being requested.packages/daemon/src/graph/graph-completion.ts:288- When a graph has an announcement route butdeps.sendGovernedAnnouncementis undefined,handleGraphCompletionnow recordsannouncementDelivery: "unavailable", skips delivery entirely (line 296 gates on!== undefined), writes run metadata, and returnsok(undefined). Before this branch the same state fell intosendGoverned, which loggedlogger.errorwithmissingPrerequisites: ["sendBoundary"]and an actionable repair hint (graph-announcement-delivery.ts:59-66) and returnederr. The new path emits nothing above INFO — the only evidence is one field on the "Graph execution complete" INFO line — so a wiring regression that drops the governed sender would silently swallow every graph completion announcement while the coordinator reports success. This is currently unreachable in production (createAnnouncementDeliveryalways returnssendGovernedAnnouncement, and daemon.ts:502 only spreads a truthy value), which is precisely why the missing WARN matters: nothing else would surface the regression. Emit alogger.warnwitherrorKind: "precondition"and a hint naming the governed-announcement boundary on the"unavailable"branch. Contrast the sibling branches at lines 292-295 and 298-301, which both keep theerr+ WARN contract.packages/daemon/src/wiring/setup-delivery.ts:663- This round-1 finding was selected for fixing but the fix round did not touch this file — the missing-authority branch is still a singlelogger.debugfor every origin. The demotion is correct for the neworigin: "channel:attachment"path (attachments delivered outside a resolved turn are routinely skipped), but it also silences the pre-existing turn-bound text-delivery case: ifctx.deliveryAuthority/ctx.destinationEndpointbinding regresses for ordinary replies, mirroring stops and the agent loses own-utterance continuity across restarts with zero evidence at the default log level, against CLAUDE.md's rule that diagnosability must not depend onlogLevel: debughaving been set before the incident. Branch onevent.origin: DEBUG forchannel:attachment, WARN with the priorerrorKind: "precondition"+ hint for a turn-bound text delivery.packages/core/src/security/secret-detection.ts:148- Noting the residual delta for the record, not asking for a change.NON_CREDENTIAL_STRUCTURE_RErestores the base's denylist form but widens it from[\s:/?&=@,]to also exclude; ' "( ) [ ] { } < > \ |. Verified that the minimum needed for the motivating false positive (document.getElementById('runName').value.trim();— 48 chars, H=4.34, not excluded under the base regex) is only(,),'; the extra characters shrink the last-resort entropy net relative to base f8c4401 for an unlabelled 44+ char credential that happens to contain a semicolon, quote, bracket, angle bracket, backslash, or pipe. Password punctuation (! # $ % ^ * ~ + - _ .`) is back inside the net, and the labelled-assignment paths are unaffected, so the tradeoff is narrow and the code documents it — recorded so the intent's "do not weaken checks" criterion is evaluated against a known, bounded delta rather than an unexamined one.✅ **Test** - passed
✅ No issues found.
CI=true npx vitest run <68 changed packages/**/*.test.ts>— every changed package unit test file (4350 tests)CI=true npx vitest run test/architecture/locale-pack-ids-doc-parity.test.ts scripts/contracts/real-user-target-contract.test.tscd test/live/self-driving/scripts && CI=true npx vitest run --config vitest.config.ts— live-kit driver/oracle project (16 files, 173 tests)CI=true npx vitest run -c test/live/vitest.config.ts test/live/scenarios/channels/telegram-attachment-mirror.test.ts test/live/scenarios/channels/telegram-delivery-roundtrip.test.ts— Stage-B real grammy adapter → loopback Telegram emulator → production-schema delivery_mirror (Stage-C skipped: needs COMIS_LIVE credentials)CI=true npx vitest run -c test/live/vitest.config.ts test/live/assert/channel-trace.test.ts test/live/harness/rig.test.ts test/live/scenarios/channels/{signal-foundation-proof,telegram-acceptance-vl,telegram-groups,telegram-reaction-learning}.test.tsCI=true npx vitest run -c test/vitest.config.ts test/integration/config-posture-wiring.test.ts— boots a real daemon, asserts the exec-sandbox relaxation reachesobs.system.healthCI=true npx vitest run -c test/vitest.config.ts test/live/self-driving/scripts/remote-root.test.tsCI=true npx vitest run test/architecture/generic-runtime-boundary.test.ts— the domain-neutral runtime gate named in the intentCI=true npx vitest run test/architecture/{contract-codegen-drift,contract-bundle-size,contract-handler-parity}.test.ts— gates over the regenerated web API contractsCI=true npx vitest run test/architecture/{autonomy-skill-no-drift,bundled-skills-declare-requirements}.test.ts— bundled deep-research SKILL.md mirror paritypnpm build(needed by the integration/live dist-aliased tiers)Manual evidence run:npx tsx /tmp/no-mistakes-evidence/01KZT7E7CH69P982R352SZ9CY2/attachment-mirror-evidence.mts— drove the daemon's owninstrumentAttachmentDeliveries+setupDeliveryMirrorwiring against the Telegram emulator and dumped the persisteddelivery_mirrorrowsManual evidence run:node /tmp/no-mistakes-evidence/01KZT7E7CH69P982R352SZ9CY2/graph-record-writer.mjs(realwriteRunMetadatafrompackages/daemon/dist) thenCOMIS_DATA_DIR=… node packages/cli/dist/cli.js explain <graphId> --graph --offlineManual evidence run:node /tmp/no-mistakes-evidence/01KZT7E7CH69P982R352SZ9CY2/reply-transcript.mjs— rendered the chat text a user receives from the built outbound-evidence guards and locale catalogpackages/daemon/bundled-skills/deep-research/SKILL.md:1- Out-of-scope consolidation worth a follow-up:skills/<name>/SKILL.mdandpackages/daemon/bundled-skills/<name>/SKILL.mdare two byte-identical hand-maintained copies of the same 7 shipped skills, and this change edited both copies ofdeep-research/SKILL.mdin lockstep (+17 each) to add themin-distinct-web-*floors and the receipt-ledger procedure. No gate enforces parity between the trees (test/architecture/has no deep-research or skills-tree check;packages/daemon/package.jsonjust shipsbundled-skillsverbatim), so the next edit to one copy silently ships a stale bundled skill while the repo-visible one reads correct — anddocs/skills/manifest.mdxcitesskills/deep-research/SKILL.mdas the authoritative example while the runtime seeds from the bundled copy. Fixing this properly means either generating/copying the bundled tree fromskills/at pack time or adding an architecture parity gate; both are build/packaging changes beyond a documentation pass. All 7 overlapping pairs are currently in sync, so nothing is stale today.🔧 Fix: name the shipping skill tree as single owner
1 info still open:
packages/daemon/bundled-skills/deep-research/SKILL.md:1- Follow-up proposal, doc half resolved: AGENTS.md §6.5 now namespackages/daemon/bundled-skills/<name>/SKILL.mdas the only tree that ships and seeds, records that the repo-rootskills/tree is a non-shipping mirror of seven of those skills, and states the edit-both rule — so the misdirection that let this change touch two hand-maintained copies in lockstep is documented at its owner. The enforcement half remains open and cannot be done in a documentation phase: byte parity is gated fordeep-researchonly (scripts/contracts/real-user-target-contract.test.ts:88), leavingchart-visualization,find-skills,image-generation,log-troubleshooting,podcast-generation, andvideo-generationfree to drift silently. Closing it means either an architecture parity test over all seven mirrored pairs or generating/copying the mirror from the shipped tree at build time — both are test or build changes this phase is forbidden to make. All seven pairs are byte-identical today (verified withdiff -rq), so nothing is stale right now.✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.