Repository navigation
PTYCAP-08: periodic task QC (deterministic auditor, flag OFF) [QC BLOCKED] - #513
Draft
finedesignz wants to merge 142 commits into
Draft
finedesignz wants to merge 142 commits into
finedesignz wants to merge 142 commits into
Conversation
Goal-backward verification of Phase 1 (PTY token accounting, #395) and Phase 2 (PTY pre-flight gate, #493) against ROADMAP success criteria, with every proving test run per-file. - Phase 1: 3/3 SC implemented; gaps_found (G-1 MAJOR: emitter dedupes on record uuid, not message.id, so the PTY ledger over-counts; G-2 MINOR: live-Postgres proofs not observed locally). - Phase 2: passed 3/3; three MINOR gaps (CRLF-fragile guard test, stale docs mechanism claim, Telegram permission keystrokes un-preflighted). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Read-only recon of the gate chain, actor inference, PTY write paths, counters, owner notification, token-cap defaults and kill-switch precedents, with file:line evidence. Input to discuss/plan for the governed-automation guard and the lifetime counter + kill switch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ONTEXT Unattended discuss for Phase 3 (governed-automation guard): the eight design forks were answered by a claude+codex+agy design-fork panel (record in GATES/design-fork-1.md, VERDICT PASS with amendments). CONTEXT captures the binding decisions D-01..D-17: governance primitives only (no PTY byte-producer), fail-closed lifetime/kill-switch slots, enabled-ceiling rule, call-time flag default OFF, hard rename with eligible-actor rule, automation-only governed chain (human chain untouched), door pins. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Planner (opus) output verified by gsd-plan-checker: 0 blockers, 2 warnings (fails_when pass-count floors; plan 03-04 doc-heavy scope), accepted for execution. Waves: 03-01 tracer (governed-pty module + rename + OFF==legacy differential), 03-02 preflight automation branch + CRLF fix, 03-03 door pins + spoof tests + Telegram required source, 03-04 docs/OpenAPI/baseline gate. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…with OFF==legacy differential - add hub/src/dispatch/governed-pty.ts: flag reader, eligible-actor rule, four governors (kill_switch/lifetime_counter fail closed), test-only DI, governedAutomationPtyGate - export isDailyTokenCapEnforced from gates.ts - telegram dispatch composes governedAutomationPtyGate - add differential test against a frozen legacy oracle and flag-ON telegram cases Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tionPtyGate - ask and work compose governedAutomationPtyGate with unchanged server-inferred resolvers - pin that an external-ask actor stays blocked with the flag ON and every governor passing Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rnor semantics - remove humanOnlyPtyGate from gates.ts (hard rename, no alias); keep AUTOMATION_ACTORS and humanOnlyRejectsActor - human-only-guard test targets governedAutomationPtyGate with the flag pinned OFF - pin governor order, enabled rule, fail-closed slots, throw, non-PTY, DI-only and no-alias Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…preflight - automation actor refused before any DB gate unless the governed-automation flag is ON - flag ON: spend chain then governors, prefixed reasons; throw/hang stay fail closed - human chain and scanned gates literal untouched Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… humanInteractive guard CRLF-safe - no governor in either chain constant; human turn passes with fail-closed governors and flag ON - split source on optional CR plus LF (Phase-2 MINOR-1) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ed when missing The webhook and the doctor replay assert source 'human' at the authenticated boundary; a call without a source is refused on a pty-interactive session instead of defaulting to human (D-09 iv). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s and preflights as human - term.input with source/actor extras -> preflight actor human, forwarded keys exactly type/session_id/bytes - term.attach_file stays preflight-exempt (D-10) and forwards no source/actor keys Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…outing, privileged callers, flag/DI, exemptions - emitter allowlist (ws/client.ts, telegram/transcript/pty-inject.ts) with non-vacuous self-check - supervisor canary: user_message/permission_response never touch the PTY, term.input does - caller pins for automation/human actor, preflight, injectPtyKeystroke, dispatchToSession - flag/DI literals confined to dispatch/governed-pty.ts; actor-inference and Telegram source pins - EXEMPTIONS record: injectPtyKeystroke and term.attach_file Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-2 mechanism claims, Phase-4 hand-off - usage-cost.md: PTYCAP Phase 3 section; structural reason automation cannot reach the PTY - CLAUDE.md: REMO_GOVERNED_AUTOMATION_PTY env bullet, docs-map row, invariant, token-cap fail-closed fix - ROADMAP: Phase 4 hand-off note (no SC change) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ate rename across docs and SESSION-ASK spec Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…onPtyGate; finish rename in hub/src comments Comment-only source changes; docs:sync regenerated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…59 fail 0) with phase-3 accounting Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nity) ceiling config maxInjectsPerHour() coerces non-finite env to the default 4, so the governor passed an invalid value. Add isInjectRateConfigured() (raw validity, governor only; legacy gate behavior unchanged) and align docs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…am/doctor.ts) doctor.ts takes dispatchToSession as an injected dispatch param, so the bare call-site needle missed it. Pin importers instead (webhook + doctor), and assert the doctor replay call passes source: 'human'. Docs name doctor.ts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… pass) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Eight executable plans (G-1 emitter fix first, tracer-led controls core, counting expansion, PTY door + governors, owner surfaces + 60% alarm, kill-switch coverage, spawn-site guards, e2e + docs + 20M cap last), VALIDATION map with source coverage audit, and 04-FORKS.md recording planner forks for panel confirm or overturn. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Apply the locked fork-panel verdicts and the plan-check fixes: heal route classified machine (F-2), separate final halt check before send (F-3), release resumes every scope and once-task re-arm (F-4), 80 percent lifetime warning page (F-5a), triage key per application (F-5b), one atomic lifetime + de-duplicated rate-union reservation with routine_run_log.inject_token (F-6), zero new skipped tests with the DB proof moved into 04-02 via an existing e2e test body (F-8). 04-02 split into 4 tasks, 04-03 gains a run-log token task, 04-07 gains a heal task, 04-08 reduced to docs + cap-last-code-commit. Includes 04-FORKS-PANEL.md and 04-PLAN-CHECK.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ima and positive deltas - G-1/D-15: records of one assistant message share message.id and carry cumulative usage; count once - key = message.id, fallback uuid; negatives clamp to 0; maxima never decrease; replay emits nothing - FIFO bound SEEN_UUID_CAP kept; six new fixtures in pty-usage-tail.test.ts Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- registry.registerInternal and catchup.runOnce skip task_qc rows unless the flag is ON (4 lines) - end-to-end flag-off suite: load, register, replace, catchup, fire, seed, email - harness gains listEnabledTasks; seed.ts added to the closed import allowlist Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- global, user and env halts skip with automation_halted:<scope>, no engine, no email - isAutomationHalted receives an undefined sessionId; a session-scoped halt does not stop the run - release resumes; a malformed row with a session_id fails closed Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…an summary Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ncy helper - runTaskQcSchemaChecks: CHECK re-apply with task_qc rows, per-user partial unique index, NULL session anchor, findings constraints, dedupe, ENGINE claim, cascade - runTaskQcEngineChecks: report-only row snapshot, three allowlisted fixes with executed rollback SQL, writer row lock, in-flight refusal, atomic run claim - no test() calls: invoked from existing gated tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…2e bodies Zero new tests, zero new skips; executes in Woodpecker postgres:16 only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… rationale in the specs - 08-SPEC TQC-07 rewritten as deterministic/no model; knob table, TQC-03 (three kinds), DDL updated - 09-SPEC AR-3, CQ-04, knob table and CQ-05 examples follow the three-kind allowlist - 08-CONTEXT gains dated Planner decisions; 08-FORKS/CONTEXT cost rationale corrected - task-qc-spec-supersession.test.ts enforces it Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- docs/scheduled-tasks.md: Task QC section (detectors, three fixes, arming order, bounds, digest, API, seed) - CLAUDE.md: four env knobs, constants-not-knobs, no token cap, docs-map row - docs/usage-cost.md: taskqc:<userId> counter key family Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
executeChain now reads the child row through the DAL to refuse a task_qc child (plan 08-03), so the DB-free smoke hit Postgres (ECONNREFUSED) and broke the check-baseline fail_max gate. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…added to tsc The phase gate requires the tsc error count not to exceed the 427 recorded before the phase. Types only (cast through unknown, as any on test json bodies, ts-expect-error on cache-bust imports). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d (skip stays 259) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…mary Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eck (codex MAJOR 2, MAJOR 3) MAJOR 2: every QC transaction now arms the remaining pass time as SET LOCAL statement_timeout before any lock wait and before each read statement; a database cancellation (57014/55P03) is treated as the deadline passing (truncated, unpersisted 'deadline' proposal, fix tx rolled back whole). The app-uuid resolver is raced against the deadline. Engine lookups and proposal inserts run in armed transactions. MAJOR 3: the safe-fix writer takes pg_advisory_xact_lock on 'taskqc-session:' || session_id between its row lock and the in-flight probes; scheduled_task_runs gets a BEFORE INSERT trigger taking the same lock (additive, CREATE OR REPLACE, schema-lint pragma), so a run for any task on the session either commits before the probe or waits for the writer. The task row lock is now FOR NO KEY UPDATE so it cannot deadlock against the FK key-share of a concurrent run insert (lock order row -> session on both sides). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…(all three seats, MAJOR) PATCH on a non-task_qc row with task_type 'task_qc' now returns 400 task_qc_machine_seeded before any write, matching the POST guard, so the generic path can no longer mint an auditor row that skips the hourly cadence floor and the system-row protections. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ness MINOR 4) target_offline, no_online_supervisor, launch_pending and the daily cost cap reasons are not a task defect and no longer produce a propose_disable. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…y at restart or next edit (correctness MINOR 3) The writer corrects the stored column only; the cron job reads its timezone when armed. The applied block now states that instead of implying it is live. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…er comment (correctness MINOR 2, 6) Proposal rows get digest_sent_at (additive column). A same-day conflict re-returns the row while it is undelivered; the sender marks rows delivered only after a successful digest send, so a failed send or a same-day re-run no longer drops findings, while an already-delivered row is still not re-mailed. The sender comment now states the real dedupe (owner-local day) and documents the mid-pass kill-switch window for the read-only digest. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…, session lock, delivery marking, PATCH guard) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n rows instead (codex round 2 MAJOR 1, 2) The round-1 BEFORE INSERT trigger put an advisory lock on every session-bound scheduled_task_runs insert even with Task QC off, and its NULL-session skip plus FOR NO KEY UPDATE reopened an own-run race for supervisor runs. schema.sql now drops the trigger and function if present (idempotent, no lock on a converged boot). The safe-fix writer takes the task row FOR UPDATE (a run insert's FK key-share conflicts with it, session-bound or NULL-session) and the target sessions row FOR UPDATE (scheduled_task_runs.session_id references sessions) before probing, so run insertion is the unchanged pre-feature SQL. Tests: task-qc-run-insert-untouched (insert SQL pinned, no trigger), task-qc-in-flight (lock order, null-session), task-qc-schema. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…OR 2, still open) - boundedBegin: the wait for a pooled connection is raced against the deadline for the read, proposal and fix transactions; a transaction that acquires its connection late rolls back before issuing any statement. Only acquisition is raced, so a write transaction is never abandoned half-way. - applyFix re-arms statement_timeout with the time left before EVERY statement (lock, session lock, probes, UPDATE, audit insert), not once per transaction. - haltCheck is raced against the deadline; an unanswered check is treated as not cleared to write (deadline), never as not halted. - The sender shares one run deadline with the engine: the digest email request is capped to the time left (sendEmail timeoutMs), nothing starts past it, and the delivery mark runs in a transaction with its own statement_timeout. Tests: task-qc-deadline (slow pool for read and fix transactions, per-statement re-arm, deadline between UPDATE and audit insert, never-answering halt check), task-qc-tracer (email bound, mark timeout, no send past the deadline). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ex round 2 MAJOR 3) A digest cuts findings at the 200-finding and 100k-char caps, but the sender marked every recorded row delivered after any successful send, so a cut finding stopped being re-reported that day. buildDigest now returns the findings it rendered, the engine returns recorded rows keyed by finding (replacing recordedIds), and the sender marks only rows whose finding was shown. Test: task-qc-tracer size-cut digest marks exactly the rendered rows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…(codex round 2 MINOR 5) Detection reads target_id ?? session_id, but the rendered rebind command guarded only session_id, so a target-only stale binding made it a no-op. The command now rewrites whichever column holds the stale id (as the safe-fix writer does) and matches on either. Tests: task-qc-proposals, task-qc-digest-escape. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…the history bound (codex round 2 MINOR 4, 6) SKIP_FOREVER compared reasons after the 120-char render cap, so two long reasons differing later grouped; it now compares the full normalised reason and truncates only the rendered evidence. The detector window now filters ignored statuses (cancelled, non-terminal) before taking the newest N, and the history read ranks counted and ignored statuses in separate partitions so the per-task bound can no longer be consumed by ignored runs (the ignored partition still supplies the NEVER_FIRED existence signal). Tests: task-qc-detectors, task-qc-load. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…icity, hard deadline, rendered-only delivery marking) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SC1-5 and all fork-panel amendments verified against code and tests; 1 open MAJOR (sender whole-run deadline) re-confirmed, PG-only proofs CI-pending. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… acquisition, in-callback recheck) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
AgentAutofix AI ReviewclaudePASSED
codexPASSED No findings. agyadvisory -- not part of the gate decision PASSED No findings. Result: Both AI reviewers passed Reviewer models (requested pin, not independently confirmed):
|
Contributor
|
AgentAutofix did not auto-merge this PR. Blocking reason: CI is failing on the reviewed commit: Reviewed commit: |
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.
PTYCAP Phase 8 - Periodic Task QC + Optimization
Status: DRAFT - /qc BLOCKED (1 open MAJOR after 2 fix rounds). Feature flag default OFF = true no-op.
What it builds
hub/src/task-qc/) - NO model turn. Guard tests prove a run produces no user_message, dispatch, session launch, chain_task or token_usage.__internal_*rows never flagged; log_checkskippedis clean).recompute_next_run_atis a proposal, not a fix.scheduled_tasksrowtask_type='task_qc'(additive CHECK-list update; boot seed idempotent, before registry/catchup); API refuses POST/DELETE and any repurposing PATCH (incl. converting another task to task_qc).taskqc:<userId>; kill switch inherited.from_inbox_id) with one proposal per non-fixed finding; only rendered findings are marked delivered.QC
Seats: sonnet correctness + adversary lenses, Codex read-only (agy MISSING). Record:
.planning/phases/PTYCAP-08-task-qc/QC/.Open MAJOR (QC/VERDICT.md): the sender's whole-run deadline is not hard (deadline starts after recipient query/reservation;
markDeliveredpool acquisition unbounded).Verification
bun run check-baseline: OK (pass 3165, skip 259, fail 0); floors unchanged.🤖 Generated with Claude Code