Commit Graph
237 Commits
Author SHA1 Message Date
ZacharyZhang-NY c1349fceab Fix OAuth prompt dismissal on terminal status 2026-04-22 20:02:28 -04:00
ZacharyZhang-NY 6413a9374d test(orchestration): guard workspace safety net removal 2026-04-22 19:28:36 -04:00
ZacharyZhang-NY 6da0a58769 refactor(db): group database domain modules 2026-04-22 19:24:25 -04:00
ZacharyZhang-NY e43a89096d refactor(main): audit warning suppression rules 2026-04-22 19:16:22 -04:00
ZacharyZhang-NY a7934d2111 refactor(ipc): split company operation handlers 2026-04-22 19:11:45 -04:00
ZacharyZhang-NY 9d38ec20f1 fix(ipc): expose classified handler codes 2026-04-22 19:07:08 -04:00
ZacharyZhang-NY 1883d9d9d3 fix(errors): warn on raw stringify fallback 2026-04-22 19:04:53 -04:00
ZacharyZhang-NY ee1ea4fd8c test(db): cover agent hierarchy cycles 2026-04-22 19:02:54 -04:00
ZacharyZhang-NY bbf7ab91e2 fix(renderer): preserve desktop result errors 2026-04-22 19:00:53 -04:00
ZacharyZhang-NY 7793f2da35 fix(connectors): guard pi provider resolution 2026-04-22 18:58:30 -04:00
ZacharyZhang-NY 0d9f4f15eb refactor(automation): register workflow actions 2026-04-22 18:54:31 -04:00
ZacharyZhang-NY 8bf2299092 test(prompt): lock cacheable system prefix 2026-04-22 18:45:02 -04:00
ZacharyZhang-NY 8148877b4a fix(runtime): preserve inbound correlations for active runs 2026-04-22 18:43:05 -04:00
ZacharyZhang-NY dca148a125 fix(prompt): render skills without pi shape casts 2026-04-22 18:39:56 -04:00
ZacharyZhang-NY 9f35dc7446 fix(runtime): erase pi tool array type safely 2026-04-22 18:37:03 -04:00
ZacharyZhang-NY 710448a75f fix(preload): keep zod out of sandbox bundle 2026-04-22 18:31:24 -04:00
ZacharyZhang-NY fa006524c2 refactor(runtime): centralize lifecycle constants 2026-04-22 16:58:36 -04:00
ZacharyZhang-NY e540cbb2a6 refactor(service-graph): replace late bindings with event hub 2026-04-22 16:55:20 -04:00
ZacharyZhang-NY 9e712f2746 refactor(ipc): generate preload forwarders from registry 2026-04-22 16:49:02 -04:00
ZacharyZhang-NY 612a760152 fix(runtime): move team building policy into tools 2026-04-22 16:38:59 -04:00
ZacharyZhang-NY 473486aa61 refactor(runtime): unify run attempt policy 2026-04-22 16:33:41 -04:00
ZacharyZhang-NY 775598ef4c fix(db): make task row state authoritative 2026-04-22 16:24:57 -04:00
ZacharyZhang-NY ebcc15c68d fix(runtime): derive unattributed cost from usage status 2026-04-22 16:18:03 -04:00
ZacharyZhang-NY f107415f4f fix(browser): execute social actions through cdp 2026-04-22 16:14:09 -04:00
ZacharyZhang-NY fb6d2a0d77 fix(runtime): tokenize context compaction budget 2026-04-22 16:00:12 -04:00
ZacharyZhang-NY 212e03219d fix(artifacts): classify projection filesystem errors 2026-04-22 15:48:00 -04:00
ZacharyZhang-NY eefb515aa2 fix(runtime): classify run usage status 2026-04-22 15:41:19 -04:00
ZacharyZhang-NY e3eb45b08d fix(landing): sync first-run narrative 2026-04-22 15:30:10 -04:00
ZacharyZhang-NY f8ed2aa666 fix(landing): derive platform support from release assets 2026-04-22 15:15:10 -04:00
ZacharyZhang-NY 1453a8fa95 fix(renderer): preserve desktop error codes 2026-04-22 15:00:35 -04:00
ZacharyZhang-NY eec26a09a3 fix(release): execute d1 migrations without shell 2026-04-22 14:52:54 -04:00
ZacharyZhang-NY f90fb037f9 docs(runtime): separate pi dependency boundary 2026-04-22 14:39:19 -04:00
ZacharyZhang-NY feffd72b98 fix(runtime): run pi tools sequentially 2026-04-22 14:37:35 -04:00
ZacharyZhang-NY 64842a9185 fix(runtime): guard pi stream setup failures 2026-04-22 14:36:16 -04:00
ZacharyZhang-NY 5155136937 fix(api): require api server callbacks 2026-04-22 14:27:49 -04:00
ZacharyZhang-NY 529bb109db fix(runtime): preserve tool result facts in compaction 2026-04-22 14:22:28 -04:00
ZacharyZhang-NY 6dfa1a851d fix(runtime): compact context inside worker 2026-04-22 14:19:46 -04:00
ZacharyZhang-NY 33c6ede381 fix(runtime): fail runs on context input errors 2026-04-22 14:13:59 -04:00
ZacharyZhang-NY 43583ef30b fix(runtime): gate cofounder checkpoints 2026-04-22 14:05:26 -04:00
ZacharyZhang-NY 7a1dd647aa fix(api): make task updates transactional 2026-04-22 14:00:24 -04:00
ZacharyZhang-NY 19f8494d09 fix(db): make filesystem lock intent explicit 2026-04-22 13:51:41 -04:00
ZacharyZhang-NY 0785c9ba47 fix(db): make task checkout atomic 2026-04-22 13:38:54 -04:00
ZacharyZhang-NY 97033dfabd update 2026-04-21 12:44:33 -04:00
ZacharyZhang-NY 1f2f9770a6 Hotfix: separate workspace observation from lock claim — restore artifact projector for cognitive runs
Production regression of T1 (7829acc..15e3863). User reports "明明生成
了很多文件,但只有一个" — the filesystem shows 19 markdown deliverables
in ~/Documents/Github/test/{business-plan,operations,ceo-coordination}/
but the DocumentCenter surfaces only one row.

Root cause is structural, predicted in spirit by Karpathy's Round 1
take ("把'认知'和'执行'两件事一起锁是数据结构错"). The T1 rewrite
collapsed two concerns into one nullable field on the run context:

  workspacePath = workspace?.localPath ?? null
                  ^^^^^^^^^                ^^^^
                  lock target              observation root

For lockMode='none' (every cognitive C-suite agent post-T1) the
resolver returns workspace=null, so workspacePath was null, so
artifact-projector.ts:242 short-circuited every projection with
`{ kind: "skipped", reason: "no_workspace" }`. The agents kept
writing files via bash (cwd falls back to the company default
workspace at worker/runtime/index.ts:142), but nothing observed
them — the DocumentCenter only saw the one file that was projected
back when the agent still held an exclusive workspace.

Fix: split the two concerns. WorkspaceResolution gains a non-lock
`observationPath` field; the resolver populates it from the company
primary workspace (new `getCompanyObservationWorkspace` query —
primary first, oldest second, null only when company has zero
workspace rows) for lockMode='none' runs, and from `workspace.localPath`
itself for lockMode='exclusive' runs. RunDispatchParams threads the
field through; turn-context's `workspacePath` reads it first.
artifact-projector.ts is unchanged — it just sees a non-null path
again and resumes baselining, diffing, and upserting work_products
rows the way it did pre-T1.

Three new unit tests pin the regression: cognitive role with
workspace ⇒ observationPath set; cognitive role with no workspace ⇒
observationPath null; exclusive ⇒ observationPath equals
workspace.localPath. typecheck green, 543/543 unit tests, 10/10
eval. No fallback, no mock, no silent degradation.
2026-04-20 16:22:40 -04:00
ZacharyZhang-NY 28cdf7c56f Rewrite resolveWorkspace to per-task lockMode inference; drop company_fallback silent share (B4-adjacent)
Old resolver: task → agent → project → any company workspace, all
marked exclusive. That fourth step folded every runnable agent in a
multi-agent company onto a single workspace row and serialised the
C-suite (four agents, one exclusive lock, three starved).

New resolver: lockMode='exclusive' is now an opt-in decision inferred
per task. Three rules:

  1. task.workspaceId set → exclusive on that workspace (explicit).
  2. filesystem signal (task.requiresFilesystem OR agent in a
     coding role/engineering department) → exclusive on
     agent.workspaceId / project primary; throws if neither exists.
  3. otherwise → none / null. Pure cognitive work runs with no
     workspace lock and fully in parallel.

Removed:
  - company_fallback silent-share path. Filesystem-touching runs
    with no legitimate binding now throw WorkspaceConfigurationError
    at resolve time so the caller decides recovery rather than the
    resolver picking a random shared workspace.
  - workspacesMod.getAnyCompanyWorkspace (now dead code).

Invariants now enforced by types:
  - lockMode='exclusive' ⇒ workspace is a live WorkspaceRecord.
  - lockMode='none'      ⇒ workspace is null.

Tests updated to cover the new decision table and the four-non-
coding-agents parallel case that was the original bug.
2026-04-20 15:32:01 -04:00
ZacharyZhang-NY d2b6f91023 C4 follow-up #3: RFC 8594 Deprecation/Sunset headers + call counter on legacy hire routes 2026-04-20 14:56:34 -04:00
ZacharyZhang-NY 1fad88bad1 C4 follow-up #1: split canFileCeoStrategy from canRequestHire for file_approval tool scope
Old internal-tool-selector attached `file_approval` to any agent with
`reportsTo === null`, and attached both tools through the same
management-keyword predicate chain. That let a VP or director with
org-management authority walk away with `file_approval`, contradicting
the C4 commit narrative that scoped `approve_ceo_strategy` as CEO-only.

Introduce `canFileCeoStrategy(db, companyId, agentId)` as a dedicated
predicate requiring both a CEO-equivalent role/title AND
`reportsTo === null`. Using either half alone is too loose: role alone
lets a demoted CEO with a virtual superior still file strategy,
`reportsTo` alone lets a VP with no manager slip through. The two
conditions together pin the predicate to a genuine top-level CEO.

- `hire_agent` continues to gate on `canRequestHire` (managers hiring
  ICs is a legitimate flow and the original "CEO-only" framing in the
  C4 commit message was narrower than the production reality).
- `file_approval` now gates on `canFileCeoStrategy`, orthogonal to hire
  authority.
- New unit test covers 4 edges: genuine CEO, CEO title with virtual
  superior, VP without manager, and plain IC.
2026-04-20 14:56:11 -04:00
ZacharyZhang-NY 54a97f67ac B2 Phase 1 follow-up: plug lease orphan gap in advanceTaskStatus + scope interruptStaleRuns cleanup
Linus review T1 surfaced three real bugs in the B2 Phase 1 shadow
dual-write surface. Fix them in one pass.

1. advanceTaskStatus left task_leases behind on terminal (done /
   cancelled / blocked) and "return to queue" (todo / backlog)
   transitions. The status->phase trigger advanced tasks.phase but the
   lease row lingered as an orphan. dev-mode verifyPhaseConsistency
   could see the divergence; production silently drifted. Wrap the
   status UPDATE and an explicit DELETE FROM task_leases in a single
   transaction so no caller observes the intermediate state.

2. The no-restricted-syntax guard in eslint.config.mjs only matched
   literals shaped "UPDATE tasks SET status" -- advanceTaskStatus's
   dynamic `UPDATE tasks SET ${timestampSets.join(", ")}` slipped past,
   and so did saveTask / recoverStaleLocks (status not first column).
   Tighten the selectors to (a) match any status-write within UPDATE
   tasks regardless of column order, and (b) flag template literals
   whose head ends with `SET ` so dynamic helpers must carry an
   explicit eslint-disable with rationale. Five grandfathered sites
   now carry matching disables.

3. interruptStaleRuns scoped its task+lease cleanup with
   `WHERE finished_at = ?` against the freshly stamped timestamp --
   safe in isolation, vulnerable to ISO-millisecond ties with other
   already-interrupted runs. Capture the stale run ids before
   mutating anything and drive every downstream statement from that
   explicit id list. Original semantics preserved; scoping is exact.

Unit tests added in tests/unit/tasks-phase.test.ts cover the
advanceTaskStatus lease cleanup across done / cancelled / blocked /
todo, and pin the in_review case as "lease stays".
2026-04-20 13:51:53 -04:00
ZacharyZhang-NY 118e3d8795 Remove final AppDatabase pass-through methods with ESLint guard (C1 part 3/3)
Migrate all remaining pass-through call sites (social, skills, budget,
entityCrud, documents, knowledge, automation, wakeup, backup, threads,
settings, snapshot, connectors, workspaces, activity) to their owning
domain modules. `AppDatabase` now carries only three methods:

  - createHireRequest (multi-module composite: agents + approvalsMod)
  - rollbackConfigRevision (multi-module composite: documents + entityCrud)
  - queryAll (raw-SQL escape hatch, @internal)

The vault/env-binding infrastructure previously passed argument-by-
argument into `entityCrud.saveSecret`/`resolveSecretEnv` now binds at
module construction, letting callers invoke `db.entityCrud.saveSecret({...})`
without carrying vault plumbing.

Structural types that narrowed AppDatabase to a bag of flat methods
(`ConnectorModelPolicyDeps` callers, `CapabilityMatchDb`, test mocks in
budget-enforcement / budget-incidents / task-quality-gates /
failure-escalation / task-quality-gates-sweep) are reshaped to the new
namespace. `connectorPolicyDepsFromDb` replaces the old pattern of
handing the whole AppDatabase to `validateConnectorModelSelection`.

A new ESLint rule in eslint.config.mjs blocks new top-level methods on
AppDatabase so the pass-through layer cannot silently grow back.
`AppDatabase.ts` dropped from 193 lines to 58; `AppDatabaseBase` lost
the 270-line trailing pass-through block.
2026-04-20 13:31:39 -04:00
ZacharyZhang-NY a69fbb053b Codemod db pass-through calls: messages + runs + approvals + company (C1 part 2/3)
Rewrite ~376 call sites for messages, runs, approvalsMod, and company
domains and delete the corresponding pass-through methods on
AppDatabase / AppDatabaseBase. Structural type references
(ReturnType<HandlerDeps["db"]["getRun"]>) and SweepStaleReviewsDeps-style
mocks are updated to route through the owning sub-module.
2026-04-20 13:20:15 -04:00