Repository navigation
fix(F117): target-based guidance and post-restart delivery feedback - #218
Conversation
Every connector input used to reach the user through a two-phase shape: append a Message, then separately enqueue its Queue row. Nothing made the pair atomic, so a crash or a rejection between the halves left a message nobody was asked to look at, or a queued row with no message behind it. This registers the target contract before any producer moves onto it: one atomic Message+Queue admission per input, the closed set of producers that must migrate, and the replay cutover for rows written under the old shape. Registering the set up front is what makes Phase I closeable -- the alternative is discovering producer #7 by grep after declaring victory. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Connector inputs, scheduled wakes and hold wakes, and the manual eval trigger and CI wake all now hand over an envelope to a single admission seam instead of driving the append and the enqueue themselves. The separate trigger seam stops being a second way in. Two truthfulness fixes belong with this move. Owner provenance now fails closed rather than inheriting strict from whatever context happened to be around -- an unproven owner must not be silently upgraded. And a manual trigger now reports what its admission actually did, instead of reporting success for work that was refused. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Private input picked its winner from the Queue row, so the decision died with the row and a retry could reach a different answer. The winner is now bound to the admission receipt, and the notice commits together with the work rather than as a separate best-effort write. Also here: an external input keeps the person as its actor, not the room it arrived in; the message index moves into its own module so the queue ledger is no longer two concerns in one file; and the delivery wiring is expressed so the compiler owns it -- that wiring is exactly what the migration kept getting wrong by hand, and a type error is cheaper than a lost message. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…d set Conflict-check, limb transcripts, github-wait and the re-eval carrier each move to a single admission, one producer at a time, with the producer registry updated as each is taken. Working against a registered set is the point: each commit closes a named item rather than whatever grep turned up that day. The recurring defect across all four was the same -- a second admission that nobody had noticed was there, or a conflict labelled at a site that never looked. Two test fixes belong to that: one suite was exercising a trigger production never wired, and conflict-check's AC-C1 was restored by splitting authorization from announcement, which is what made the duplicate admission visible in the first place. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…sent The wait outbox decided whether to publish after it had already started sending, so a suppression could not actually suppress. The decision now happens at a claim taken before any send. The claim is deliberately kept out of the delivery enum. Encoding it there made a rollback unable to express 'claimed but not delivered', which stranded the row in a state no path could clear. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…e trigger chain The managed wake is the last registered producer. It is admitted once, with its lease checked before anything is written, so a superseded generation cannot write at all. Three defects found by cross-individual review are fixed with it: legacy adoption had lost its lease fence; a post-commit notification could un-admit a commit that had already landed; and the drain was sequenced behind a UI broadcast, so a failing socket fan-out left a durable wake that nothing asked anyone to look at. With every producer migrated, ConnectorInvokeTrigger has no producers left, and the whole chain is deleted -- zero references under src/. The two-phase 'append then enqueue' shape is gone from every production path, which closes Phase I. Finally, connector framing is preserved on envelopes delivered through the Queue. Without it the envelope arrives but renders as plain text: the hold-ball card, its run state and its cancel control all disappear. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…l-closed guard Category: accepted review finding "Reject coerced lifecycle response statuses", plus two sibling sites the review did not reach. All three are new in this PR. `[...].includes(String(candidate.x))` reads as a fail-closed literal check and is not one. `String(['completed'])` is `'completed'`, and any object whose `toString` returns a literal passes too, so a value that is not a string walks through a guard whose entire job is to reject it. These guards sit on recovered Redis rows and websocket frames — `RedisMessageStore`, `redis-message-parsers` and `useSocket` all gate on the shared one — so the smuggled value lands in a field whose contract is a string literal, and downstream matching silently stops working: it is neither `processing` nor a valid terminal, so projections can be suppressed and a terminal commit can conflict permanently. The fix is to compare the raw value, expressed once as `isOneOf` in the shared module rather than repaired inline at each call, so the next literal check cannot reintroduce the coercion by habit. Three sites, found by auditing the pattern across the tree instead of patching only the one that was reported: - `message-lifecycle.ts` response `status` — the reported instance. - `message-lifecycle.ts` delivery-failure `reason` — same function, one branch away. - `QueueLedgerValidation.assertQueueExecution` — the one that actually matters most: it is a throwing gate, and the coerced field is `ownerAuthProvenance`. An array was accepted as proven owner authorization. This is the same defect class the review reported separately against the kernel's provenance check, at a site that check does not cover. Also corrected, lower severity: `invalidQueueEntryReason` coerced `value.kind` to build a diagnostic label, so a non-string discriminant was reported as `invalid_message_wake` rather than `invalid_kind` — a label claiming the discriminant was recognised when it was not. Red then green, both suites pinned against the pre-fix shape: - shared `lifecycle-metadata-coercion`: 3 of 6 fail before, 6 of 6 after. Registered in `vitest.config.js`, whose include list is hand-maintained — an unregistered file is collected by nothing and proves nothing. - api `queue-ledger-provenance-coercion`: 2 of 4 fail before, 4 of 4 after. Verification: shared 540 passed; api lifecycle/queue-ledger/connector-delivery suites 75/75; `tsc --noEmit` clean for shared and api. Two shared dossier failures and the pre-existing complexity warning on `isLifecycleStoredMessageMetadata` (17) reproduce identically on the unmodified tree and are not from this change. Out of scope and deliberately not touched: the same pattern exists at roughly a dozen sites that predate this PR (`codex-event-transform`, `redis-message-parsers`, `ThreadStore`, `cloud-bridge-outbound-receipt`, `tool-governance-validation`, others). Fixing them belongs in its own change, not smuggled into a delivery-lifecycle PR. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…umer guess A finished hold kept offering "取消持球 / 取消并反馈", and one hold could show several cancel entries at once. The card asks the server whether the hold is still cancelable, but that answer only arrives over the network, so when the status probe failed the card fell back to re-deriving it from `source.meta.phase` — and that copy was wrong. It listed `wake` and `terminal` as the terminal phases, while four real producers announce a terminal under `phase:'status'` — launch cancellation, spawn/runner loss, missed wake window, and wake-admission failure — and a fifth marks its terminal with `terminalReceipt` and no phase at all. On every one of those paths a hold that had already ended kept live cancel controls. Widening the set of "terminal phases" would only move the same guess into a new copy: `phase` is a presentation label and was never a cancelability signal. Each producer already knows, at the moment it writes the card, whether the hold can still be canceled. It states that now, and the consumer stops deriving it. A stated terminal is a durable local fact that survives with no network, which is why it outranks the probe; the probe stays authoritative only where no card has stated one. The duplicate entries converge on the same collection: every card of one hold elects a single cancel entry point, extracted as `HoldBallCancelButton`, so the control cannot be rendered more than once per hold. Evidence, after two rounds of cross-individual review that both landed on the same weakness — claims that were reasoned about rather than run: - The producer contract test was inert. Written as `test/*.test.ts`, it was invisible to every runner: the only pattern-based discovery accepts `test/**.test.js`. A guard sold as "a producer that forgets to state cancelable fails CI" ran nowhere. It is plain JS now and is in the shard plan. - Stamping `cancelable` broke three exact-shape assertions on `source.meta`. Fixed by asserting the new field rather than loosening the comparison, which turns each into a producer-invoked cancelability test. - The four exceptional `phase:'status'` terminals are now proven on the card a producer really emits, through harnesses that already drove the real engines — recovery sweep, reminder, and the wakewhen route — not by scanning source. - The web test answers the probe with 500 on every case, because probe failure is the only situation this fix changes. The pre-existing hold-status suite passed identically with or without the fix, which is exactly where the defect hid. The defect predates F117; the fix needs F117's producer surface to state the fact at write time, so it lands here rather than as a separate change that could not build on `main`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
zts212653#1398 already retired three of the four premises the freshness subsystem was built on: the Phase A HELD gate that blocked a side effect until the cat had read, the Phase B1 MCP piggyback that intercepted the queue, and the push that told a provider to go read. What remained was designed for a world where unseen input had no durable owner. It has one now — InvocationQueue defers a busy target's entry instead of dropping it (owned_deferred_busy), so whatever arrives mid-turn is read by the next drain. This removes what that left standing. Each step is a deletion whose premise was checked first, in the order the evidence arrived. ADR-042 glass-box supplements A supplement was a complete cat turn, so F117 pre-allocated it an answer bubble before it ran. Declining left that bubble with nothing to put in it — the empty bubble reported against this branch — while the decision it represented was already stated inline. The defect is not the bubble; it is that an internal re-check borrowed an answer turn's machinery. Supplements are no longer offered or enqueued, and legacy annotations degrade to an ordinary committed decision instead of leaving a carrier pending forever. Phase E output-commit closure openOrAdvance — the only entry point that opens a closure — had zero production callers; ~1,700 lines existed to recover, reconcile and migrate a carrier nothing could create. Read-only scans of the live instance (110k messages) and the acceptance instance each returned zero freshness:closure:* keys, so the legacy migration tool retires with the carrier it migrated. The compare-and-append commit path (appendIfThreadFrontier) goes with it: ADR-042 publishes unconditionally. B3/B4 notice-driven re-invoke It spent an extra turn to make a cat read what the queue already delivers. The terminal hook still wrote metadata.freshnessReinvoke after its reader was removed. Phase D output-commit scan It ran once per answer turn and rewrote extra.freshness.kind to 'fresh' or 'freshness_unknown'. Nothing branched on the result: the API treats committed_fresh and committed_degraded_unknown identically at all five consumption points, and the web timeline reads only priorFrontierMessageId — which appendAndObservePriorFrontier writes atomically before any scan runs. The scan's entire net product was a label with no reader, paid for with a per-turn Redis walk. Kept, with the reason it survives - The frontier annotation: extra.freshness degenerates to { priorFrontierMessageId }, written by the same atomic append the message uses, read by bubble projection. Parsers ignore every retired verdict shape and keep only the frontier. - Provider-native freshness. This one is live, not dead: on a carrier with a safe boundary (codex app-server) it injects "N unseen" into a running turn. Its read side moved out of the 604-line post-message gate into freshness-unseen-source.ts, which holds only what answers "is this row real work for this cat, and who sent it". - The eval:freshness domain, decoupled from the deleted planes. Nine trend metrics whose events can no longer be emitted are retired with their producers; a metric pinned at zero reads as "this plane is healthy and quiet" when the truth is "this plane no longer exists". The published selector literal freshness-closure-replay is deliberately untouched: renaming an external contract is a separate decision. Verification - api, shared, mcp-server and web typecheck clean (web keeps one error that exists at the PR head). - 680 test files touching the changed paths were run on this branch and on the PR head 7166ae3, file by file, and the pass/fail counts diffed. Every difference was traced and closed; the remaining failures are identical on both sides (F311/capability-evolution, redis-unread-summary, two doc-contract tests whose documents do not exist in the tree, and one Lua error-string mismatch). - Web unit suite: 7255 pass, 5 fail, all five identical at the PR head. - Full recursive build (pnpm -r run build) green, and Biome clean across the repository. Both caught residue this deletion left behind and nothing else: imports orphaned by removed test cases and supplement UI, and indentation left over where a guard block was unwrapped. Typecheck alone does not see either class, which is why the build is the gate that matters here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Why: queued input was published into History before its response receiver and target retirement existed, while Codex app-server deltas were discarded and several UI surfaces derived independent liveness states. Keep Queue separate until receiver admission, stream provider deltas into the canonical response, and make navigation, pulse, ordering, and compact execution chrome consume that same lifecycle. [砚砚/gpt-5.6-sol🐾]
Why: Fork dogfood exposed that presentation order was maintained independently by many store writers, so hydration, streaming, projection, and background updates could disagree. Move ordering to one canonical read-side comparator, keep storage cursors explicit, and preserve the user scroll anchor when that view changes. The receiver could be written before its queued source was published, while publication recomputed a later wall-clock time and made the source appear after the response. Carry the durable Queue claim time through admission, retaining the monotonic enqueue floor. Keep response startedAt and storage cursors factual; bound only its presentation time after the latest admitted input, including inputs appended to an active run. A terminal response normally freezes at completedAt, but the causal floor wins if a later input clock overtakes it. Why (viewport follow-up): Re-sorting on every streamed chunk repeatedly moved concurrent processing cards and interrupted reading. Keep the canonical comparator unchanged; stream content in place, then commit changed card positions from a fresh snapshot in serial one-second rounds. Derive dirty rows by immutable message identity rather than writer flags, let display and scroll restoration share one viewport order, and anchor the visible paragraph or an explicitly expanded card before layout changes. Preserve immediate admission, storage pagination, and the existing lifecycle ordering tests. Upgrade the Claude Agent SDK carrier from 0.3.267 to 0.3.280. The SDK integration is introduced by this branch, so its version belongs in this PR. Peer requirements and the existing zod 3 resolution are unchanged; the API type-check is clean. The claude-agent-service baseline has the same 29 live-config lookup failures on both SDK versions. Co-creator dogfood later confirmed opus 5.5 replies through the installed 0.3.280 SDK. [砚砚/gpt-6-sol🐾] [布偶猫·宪宪/claude-opus-5-5🐾] Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Why: reconcile the existing public A2A candidate with main while retaining durable Queue, exact source/target fences and one canonical response result. Consume the verified local integration source cut without making fork integration history a public ancestor. UI and contract commits follow in this same unpublished candidate; gates bind the completed cut, not this intermediate tree.
Why: complete the original RFC result ownership on active/background/history surfaces, remove read-stage and recovery notices, and fold timeout/CLI diagnostics into the original response. Preserve real user actions and callback/late-socket identity fences; validate the completed public cut in this same checkout.
Why: publish the single Queue/response responsibility model and its affected consumers with the completed candidate. This implements the existing RFC, including exact failed-response wake and cancellation, rather than inventing a read stage or a new notification protocol. Operator experience, fork soak and maintainer review remain pending.
Why: the exact public candidate production build exposed seven unused bindings left after retiring read/pause/session notice presentation. Remove the unused contract parameters and imports, migrate their existing callers and fixtures, and keep ESLint enabled. Focused lint and 55 consumer tests pass; the original failed production build remains in checkpoint-6.
Why: Partial preserved readonly modifiers from the capability constant, so deleting guidance made the full Web type gate fail. Construct the absent-guidance input directly while retaining the same fail-closed assertion. Full Web types, the two fixture tests and the real response component browser check now pass; the prior production build remains unchanged.
Why: frontier adjacency and matching failure text cannot prove retry ownership. History and story playback now retain every canonical response; execution retries remain responsible for their own response identity. Actual history and replay regressions preserve unrelated private failures.
Why: startup or abandoned-turn settlement could clear a failed child before its authorized caller return was committed. Persist the original admission provenance on its response and reuse the normal atomic failed-response and Queue-wake transaction during recovery. Keep uncertain obligations pending, preserve authority and sibling identities, and make commit replay idempotent. Cover real Queue admission, startup failure and lost acknowledgements in memory and owned Redis.
Why: recovery treated an already committed failed response as a draft, trimming its content and synthesizing optional fields until exact terminal replay conflicted forever. Pass the complete durable terminal patch directly through the shared failed-response and caller-wake transaction. Processing responses keep their draft handling; committed bodies, rich/tool fields and metadata retain their original values and presence. Cover normal commit acknowledgement loss, empty fields and real Redis restart.
Why: exact-head GitHub Lint rejected the public snapshot because active F117 was omitted and completed F220 remained in ROADMAP. Correct those two inventory rows against the existing feature records without publishing fork coordination or changing execution code. The independent 0c2a0e8 code review remains applicable by identical code and dependency blobs. [砚砚/gpt-6.1-sol🐾]
Why: Queue, message bodies, references and member reads must project MessageFrom rather than infer operator identity from an absent catId. Preserve sender envelopes in socket events and reply previews, share display resolution, and keep navigation from declaring custody changes from prose.
Why: a timer callback can arrive while the sampled silence is still below the configured deadline. Re-arm the remaining interval so exact Stop never fires early, while preserving the existing CPU extension cap and once-only result.
Why: grouping still inferred a human sender from absent catId while body visibility consumed MessageFrom. Use the same identity entry point and retain source metadata in the queue preview regression.
Why: late approval reads and secondary chat-cache gaps could erase published cards or hide admitted executions. Fence request order, reconcile on reconnect and terminal events, and preserve canonical sender identity in live cards.
Why: client acceptance completes delivery and retires Queue work. Optional SDK input UUID evidence updates only the original source and target, persists through reload and remains independent of Stop, results and callbacks. Unsupported clients show a static delivered indicator without claiming model reading. Validation: Web 16/16, compiled Queue and SDK 59/59, owned Unix Redis replay and styled browser interactions pass. Full CI and operator acceptance remain separate gates. [砚砚/gpt-6.1-sol🐾]
…vidence Why: notification producers now admit through the durable Queue, and action carrier recovery joins exact source, response, child and parent evidence. Tests must exercise those contracts rather than bare MessageStore delivery or retired custody projections. Install Redis executables for owned isolated Linux tests without relaxing the existing network boundary. Validation: wait lifecycle and outbox 18/18, action lease races 7/7, schedule and task consumers 74/74. Prior CI failures retained; the full public gate remains to run on this candidate. [砚砚/gpt-6.1-sol🐾]
Why: SDK failure correlation UUIDs and synthetic API errors do not prove model consumption. Preserve consumed failed-turn lists and real main-query reply evidence while leaving Queue, Stop and completion independent. Keep absent optional delivery fields absent and construct the browser fixture immutably so current type and production gates can pass.
Why: public recovery wrappers omitted Queue and could pass lookup failures before reaching their intended dependency. Use real Queue and exact History child/parent evidence, retain scope, cancellation, expiry and parallel cases, and assert every injected fault is reached.
Why: Live admission preserves its immediate single-attempt handle. The ordinary active-writer wait loop bypassed the Live retry budget and could acquire another client after refusal. Keep ordinary member recovery while returning the existing typed Live failure without replay.
Why: cloud handoff must bind the current persisted source owner, thread and canonical sender before issuing a return grant or sending to Host. Completed responses enqueue cloud work through the real Queue; missing, deleted or mismatched sources must never reuse a prior human body or acquire return authority.
Why: keep atomic task and private wait receipt hydration together without growing the Redis store or changing its single-read authority. Fresh API build and owned Redis registration/CAS/rejection checks pass; storage and module budgets remain unchanged.
Why: the live replay already derives Queue/History and provider signals. Keeping Supplement and MCP notice certificates misrepresents the measured mechanism. Preserve retained event evidence and readiness checks; verify the generated verdict excludes retired metric identities.
Why: retired inline routing, catId guesses, Queue custody and notice writers prevented old fixtures reaching their intended branches. Keep owner, visibility, cancellation, cross-generation, fault and replay assertions on actual Queue/History/child identities; connector refusals must reach delivery, atomic failure publishes no replacement and lost acknowledgments replay once. Deny inherited runtime Redis and require explicit isolation for optional tests. Original 37-file failures are retained; current 438 checks pass with unchanged input hashes, plus focused recovery and owned Redis controls.
Why: the complete public gate reproduced cancellation before the fake gh installed its signal handler. Drive the real scheduler timeout only after readiness and hold the real child until an explicit release, preserving gate ownership and process-close assertions without depending on startup speed. Validation: original full public gate 27406 pass, one startup race, 112 skipped; retained original red and diagnostic timing probes. Corrected cleanup tests 2/2 and preflighted cleanup/request/batch/admission consumers 14/14. Full public rerun remains required. Author: 砚砚/gpt-6.1-sol
Why: owner Queue updates and cancellation share the HTTP session identity, but sockets were hardcoded to default-user. Resolve the existing session cookie on connection without trusting client auth metadata or promoting anonymous and remote unpaired clients.
Why: approval events and reconnects can arrive while a pre-change GET is active. Request version fencing alone still shares that stale physical read. Use the API client's bounded trailing generation for pending and settled refreshes, and verify the real coordinator preserves fresh results after overlap and failures.
Why: the decision sessions consumer must ask for a fresh approval owner read after a write. Preserve its unified-read assertion while verifying the coordinator option that prevents an older active GET from satisfying that refresh.
Why: API restart invalidates its session map, while Socket authority is fixed at handshake. Automatic transport reconnection could enter default-user before HTTP recovery and leave owner approval and Stop projections disconnected. Gate every physical connection on a shared fresh cookie read, preserving bounded retry and retired-surface fences.
Why: AppShell must mock the added session refresh contract, and the real Socket integration must observe disconnect before waking the existing visibility recovery path instead of assuming manager retries.
Why: post-restart feedback exposed source-kind gates blocking external continuations, duplicate execution UI and lost all-stop affordance. Reuse exact dispatch read receipts and target/run authority instead of creating another state model. Optional Signals library scans do not belong on ordinary message admission; explicit article tools remain. Retain per-source provenance, owner/revision/private/exact-parent fences, and distinguish remaining internal preparation cost from client startup. Include isolated red/green, browser, timing and original PR-slice evidence.
Why: PR217 squashed the original feature into develop_base. Both bases have the same complete tree. Join their histories without rewriting either published branch; restore the exact independently reviewed 9f8b644 implementation tree to resolve history-only conflicts. Tree identity was checked before commit.
|
独立审查与发布连续性已完成,P1/P2=0。opus的typed verdict锚点为thread_msr51149hym0i79f#0001791557530490-000176-f4eb262b,覆盖9f8b6440d6;最终984edb0da5与它全树同为bd268030e9d14c53072b9e2bfcb004e66987101c,内容diff为空。原feature与fork squash基线的树相同,历史连接仅为了保留二者祖先关系,不是新的执行代码。 六条非阻塞P3的处置:
剩余约468ms记忆/反馈内部准备没有被证明修好;这不含独立Codex客户端启动8.9s。新拆计时仅在现有串行checkpoint,并行原无准备计时,未扩大成新的遥测框架。 首次发布读回时1398新HEAD检查列表为空。更新15:01UTC:984的CI已启动,Build、Public test plan、Public contract surfaces、Directory Size Guard成功;其余运行中,serial bootstrap按计划SKIPPED。整组尚未终态,现有tracker已绑定984并会接续实际结果。fork重复CI沿operator151不要求;未自行merge、更新或重启运行实例。 |
|
PR218 merge and operator handoff completed through the standing user authorization “直接更新,更新好了我去重启” (thread message0001791547051357-000413-ccda3e64), reconfirmed when operator reported218 merged. Provider verified: MERGED2026-10-10T01:12:14Z, merge commit5875ae12b51688d59ec85402d89d6ec9e7294e37. Its full treebd268030e9d14c53072b9e2bfcb004e66987101c equals independently reviewed9f8 and published984. Runtime checkout develop_base was fast-forwarded fromd015 to5875. Old HEAD retained as local backup/runtime-before-pr218-20261010. Tracked clean; pre/post hashes of1885 protected files (including runtime configuration and untracked files) match, no original untracked file missing. No config edits, persistent storage operation or process restart was performed. Update receipt retained at/tmp/f117-runtime-update-218-receipt.json; protected file contents are not published. The operator may now use the normal restart command to accept this increment. Startup already performs its existing build/fingerprint checks; no new build/restart mechanism was introduced. Actual restart, experience and soak are still unverified. Remaining memory/feedback admission cost is still open in the original task/shared issue8. |
Why: fork #218 landed the previous candidate under a different commit identity with the same complete tree. Include its exact develop_base merge commit so the next fork PR contains only the new follow-up, without reintroducing already accepted changes. The published file tree must remain identical to independently approved 709caf8. No code, test, config, or runtime change is introduced by this ancestry reconciliation. [砚砚/gpt-6.1-sol🐾]
这份增量修复 #217 合入并重启后暴露的投递与输入区问题,直接来自原
feat/F117-1354-message-delivery-lifecycle;不包含旧 #185/#210/#215 的大差异。验证:API 271/271、前端 127/127;API TypeScript 编译通过。同 checkout 当前真实组件的桌面/手机浏览器交互通过(合成数据与内存 API,不冒称完整 Next/provider 验收)。完整 Web 检查与精确基线均只有同一个既有 TS2322,没有新增诊断。
性能边界:原内部入队→执行接纳约 1056ms,路由准备984.82ms,记忆/反馈467.75ms、关联上下文354.85ms。文章全库扫描已从关键路径删除;剩余成本及实际部署后速度仍需日志确认,不宣称整体已降至毫秒。外部 Codex 启动8.9秒单独记录。自动上下文审计已提 shared issue8。
报告与原红/绿日志、浏览器截图、输入哈希:
feature-specs/evidence/f117-feedback-2026-10-09/README.md。运行代码/配置/进程与持久数据未改。合入和更新后由 operator 择时重启;本 PR 不自行合入。独立复审:opus approved,精确 HEAD
9f8b6440d6e6528cd9716e843224ab6aff178689/ treebd268030e9d14c53072b9e2bfcb004e66987101c。独立亲跑 API284/284、来源与意图反例8/8、Web116/116;与作者计数分别报告。typed local-review fact0001791557530490-000176-f4eb262b,accepted sourcethread_msr51149hym0i79f#0001791553890412-000138-a1dca2eb,revision同一不可变消息。P1/P2=0;P3未作为额外前置。五轴风险:行为是目标能力续接、回执/停止展示、取消隐式文章注入;数据无新字段/存储且保留既有持久输入;安全保留 owner、精确执行/parent、队列版本、private/pinned 边界;契约复用原 dispatch/cancel,主动文章 API 不变;不可逆只涉及正常 feature push/PR,本 PR 无合入/运行实例操作。独立验证源选择 local semantic review,cloudReview=not-selected(现有权限边界未扩大,相关围栏和来源反例已有精确独立覆盖),fullGate=not-required(本轮受影响验证与基线类型比较覆盖了变动;不重复旧全量)。
上游 zts212653#1398 会对这个新增代码 HEAD 收取实际 CI 结果;本 fork 工作流仅针对 main,develop_base 未触发重复 CI,按 operator151 不要求再改工作流重复运行。此说明不把未运行的 fork CI 记作通过,也不沿用旧028的CI声称新代码已绿。
发布 HEAD:
984edb0da56872ee771441b0d2e9586eba5ce19b。原分支028与fork squash217基线全树一致;合并历史后的候选与已审9f8逐文件 diff 为空且全树OID相同,原feature与develop_base均为祖先。review continuity据此覆盖最终HEAD(无代码/配置/依赖/测试变化,无force push);fork PR只比较本轮增量。最终CI回执:1398精确发布HEAD
984edb0da56872ee771441b0d2e9586eba5ce19b,17项全部终态:16 SUCCESS、serial bootstrap按计划SKIPPED,0 pending/0 failures。CI运行、Windows Smoke。这是真实新HEAD CI,不是旧028的回执。fork218自身未触发重复CI,不能说fork独立跑绿。运行目录仍d015,本PR尚未合入;实际合入/更新后由operator择时重启验收。