Commit Graph
705 Commits
Author SHA1 Message Date
agent-bot ee1e53b510 fix(tests): per-package test databases + legitimate approval fixtures (issue #2 close)
CI / go-vet (pull_request) Failing after 10s
CI / backup-restore-drill (pull_request) Failing after 25s
CI / web (pull_request) Successful in 33s
Root causes of the remaining 5 CI PG failures (and the hidden flaky set):
1. All PG-integration packages shared ONE database under parallel package
   execution - migrations/seeds/truncates raced (nondeterministic failure
   sets, locally and in CI).
   Fix: RequireTestDatabaseURL/SkipIfNoTestDatabaseURL now derive a
   per-package database (<base>_<pkgHash>, advisory-lock-guarded
   CREATE); 9 raw-env straggler tests funnelled through the helpers;
   db-package tests call it unqualified (no import cycle).
2. Approval-chain fixtures were not production-shaped: freezeReviewSnapshot
   only honors head_snapshot_id, fake content hashes never froze a
   snapshot, so ApproverApprove rejected with 'approved requires frozen
   review_snapshot_id'. Errors were swallowed (_, _ =) hiding this.
   Fix (ownership-respecting, arch-enforced):
   - docrevision.SeedContentSnapshotForTest seeds the ledger tables it owns
   - docgov GovernanceEngine.FreezeHeadSnapshotForTest freezes head/review
     pointers on document_records (docgov-owned) and clears engine cache
   - all four integration fixtures use the pair; swallowed errors checked
3. Fixed-name fixtures collide once a package shares one DB (projects
   uq_projects_name_global): uniquified in projectinstance + server tests.
4. CAS/ctxmgr tests never bootstrapped migrations (relied on other packages
   having migrated the shared DB): explicit RunMigrationsOnceForTest.

Verified: full parallel short suite = 75 packages, 0 failures against an
isolated throwaway PG. CI skip list removed - short tests fully required.
2026-09-29 09:54:43 +00:00
agent-bot 375c5a42db test(config): force permission bits in perms test (umask-proof)
CI / backup-restore-drill (pull_request) Successful in 34s
CI / web (pull_request) Successful in 32s
CI / go-vet (pull_request) Failing after 39s
os.WriteFile mode is masked by umask (022 in CI turns 0666 into 0644),
making the writable-file rejection test environment-dependent; chmod the
explicit bits after write
2026-09-29 09:12:02 +00:00
agent-bot 7de9e35dcf fix(chat): bind project ID through CLI chat + stage dispatch (issue #2)
CI / go-vet (pull_request) Failing after 39s
CI / backup-restore-drill (pull_request) Successful in 30s
CI / web (pull_request) Successful in 31s
Root cause: the 2026-09-28 controlled-projection hardening added the
ErrUnboundControlledProject guard, and the server path got session project
binding backfilled - but two paths missed:
- CLI chat mode never called session.SetProjectID (only -project name)
- coordinator handleAdvanceStage built StageRunRequest without
  ProjectID/UserID, so every stage-advance squad task was rejected

Fixes:
- handleChatMode gains projectID param (wired from -project-id flag);
  session binding follows the server convention
- handleAdvanceStage passes parseDecimalID(UserCtx.Project/User.ID)
- CLI chat tests get hermetic env (unreachable DB + ALLOW_IN_MEMORY) so
  local runs stop accidentally hitting the real dev DB on :5433
- stale test TestBindSessionProjectContext_KeepsExistingProjectID asserted
  the pre-fix 'switch does not propagate' bug; updated to assert switch
  propagation + bind no-overwrite

Result: go test -short ./... = 75 packages, 0 failures (first time).
Short tests promoted from report-only back into the required CI gate.
2026-09-29 09:04:16 +00:00
agent-bot 2ad1ef393a feat(bootstrap): instance identity, single-start lock, root checks (U10c slice 1)
CI / backup-restore-drill (pull_request) Successful in 27s
CI / web (pull_request) Successful in 32s
CI / go-vet (pull_request) Successful in 14s
CI / short-tests-report (pull_request) Failing after 36s
- internal/bootstrap.EnsureInstance on the serve path: normalized writable
  roots, symlink-aware validation, data-root vs vault containment rejection,
  filesystem-root refusal
- instance-marker.json in data root: first boot creates; foreign instance
  ID fails closed (explicit adopt/migrate required, KTD18)
- instance.lock non-blocking flock detects duplicate starts locally without
  any governance tooling; ownership held until process exit
- Config.InstanceID (INSTANCE_ID env/file key; default 'default') joins the
  instance-settings bootstrap denylist (identity cannot be self-overwritten)
- auth is Bearer+localStorage per origin (no cookies) - browser isolation
  holds across ports; documented in the unit template
- deploy/systemd/agent-system@.service template (instance %i: env file,
  DATA_DIR, hardened service scope)
- tests: marker create/foreign reject, vault overlap, invalid IDs, root
  refusal, in-process duplicate-start detection
2026-09-29 08:32:15 +00:00
agent-bot 28a2c8ca2b feat(config): instance-settings fifth layer (U10b core 2, KTD16/17)
CI / go-vet (pull_request) Successful in 14s
CI / short-tests-report (pull_request) Failing after 36s
CI / backup-restore-drill (pull_request) Successful in 26s
CI / web (pull_request) Successful in 31s
- <config_root>/instance-settings.json is the final config layer:
  default > env-file(s) > process-env > cli > instance-settings
- LoadForServe wires the CLI mutation hook BEFORE instance settings;
  serve/check/explain all use it; plain Load keeps legacy behavior
- bootstrap denylist (env) fails closed (no self-locating file loop);
  SETTINGS_MODE=ignore skips the layer as the recovery path
- reflection-based typed application: string/int/bool/duration(string or
  seconds)/string-array; unknown fields and type mismatches fail closed
- group/world-writable settings file rejected; absent key = inherit
- sources table gains the instance-settings layer; e2e smoke verified
  (override applies; ignore-mode reverts to default)
2026-09-29 08:17:21 +00:00
agent-bot 93ab4802e9 feat(config): field-level source attribution via layer snapshots (U10b core 1/2)
CI / go-vet (pull_request) Successful in 13s
CI / short-tests-report (pull_request) Failing after 36s
CI / backup-restore-drill (pull_request) Successful in 37s
CI / web (pull_request) Successful in 32s
- LoadWithSources: reflection snapshots at layer boundaries (default ->
  env-file per file -> process-env incl. DSN/CORS/KB normalization); diff
  yields exact per-field source - no manual key registry, no drift
- Load unchanged signature/behavior (wrapper); ApplyCLIOverlay records the
  cli layer on a cloned config
- 'config explain' upgraded to field table (59 fields; source + set flag
  only, values never printed per KTD17)
- replaces the reporting-only key registry from PR #12
- tests: layer attribution (file/process override), cli overlay, Load regression
2026-09-29 08:06:06 +00:00
agent-bot 679028e44e feat(cli): 'config explain' with per-key layer attribution (U10b slice 1)
CI / go-vet (pull_request) Successful in 13s
CI / short-tests-report (pull_request) Failing after 35s
CI / backup-restore-drill (pull_request) Successful in 25s
CI / web (pull_request) Successful in 31s
- config.Explain(envFiles, cliOverrides): per-key source layer following the
  application precedence cli > process-env > env-file > default; registry is
  reporting-only (values still applied solely by Load); secrets never shown
- ParseEnvFileKeys shares applyEnvFile's parsing rules
- cmd/server 'config explain' resolves the same env-file stack as Load and
  renders the attribution table; smoke: HTTP_PORT/AGENT_BACKEND -> cli
- tests: registry liveness sample + layer attribution (file/process/cli/
  default) + secret masking
- full per-field snapshot with applied/desired revisions remains U10b core
2026-09-29 07:39:28 +00:00
agent-bot 2235fc7230 feat(cli): 'config check' subcommand (U10a tail, KTD16/17 minimal)
CI / go-vet (pull_request) Successful in 13s
CI / short-tests-report (pull_request) Failing after 36s
CI / backup-restore-drill (pull_request) Successful in 29s
CI / web (pull_request) Successful in 32s
- server config check: load + validate + masked summary; exit 1 on issues
- no side effects: creates no DB, starts nothing, writes no business dirs
- Config.Check() (production secrets, port range, data dir) exported for
  reuse; MaskedSummary never prints credential values
- default no-arg invocation unchanged (serve); help added
- smoke-verified: pass exit 0, invalid port exit 1 with issue line
- layer-source attribution (config explain) deferred to U10b ConfigSnapshot
2026-09-29 07:25:28 +00:00
agent-bot 95e659a915 feat(assets): embedded prompt and xlsx asset fallback (U10a slice 2)
CI / go-vet (pull_request) Successful in 13s
CI / short-tests-report (pull_request) Failing after 36s
CI / backup-restore-drill (pull_request) Successful in 28s
CI / web (pull_request) Successful in 32s
- configs package embeds agents/ + shared/ prompt assets; templates package
  embeds xlsx/ (cdo_quote.xlsx)
- template.GetAgentInstructionFile: disk-first with embedded fallback for
  instructions and writing.md (dev behavior unchanged)
- quote.CalculateAndFill: embedded xlsx fallback when the on-disk template
  walk misses (single-binary deployments)
- presence test guards the embedded asset set
- verified: vet + template/quote/bizdev/squad/arch green
2026-09-29 07:17:32 +00:00
agent-bot 686dede802 feat(db): embedded goose migrations fallback (U10a first slice)
CI / go-vet (pull_request) Successful in 19s
CI / short-tests-report (pull_request) Failing after 35s
CI / backup-restore-drill (pull_request) Successful in 27s
CI / web (pull_request) Successful in 32s
- deploy/postgres (package dbassets) embeds the full goose chain;
  RunMigrations prefers the on-disk dir (dev behavior unchanged) and falls
  back to the embedded FS when the source tree is absent (single-binary
  deployments per plan U10/KTD16)
- goose SetBaseFS global state reset after use
- TestRunMigrationsEmbeddedFallback verified against a throwaway isolated
  pgvector container: nonexistent dir -> embedded chain -> version 78,
  migration gate count agrees
2026-09-29 07:07:58 +00:00
agent-bot 2c75dcaf69 refactor(squad): AssetProvider port replaces direct template dependency
CI / go-vet (pull_request) Successful in 13s
CI / short-tests-report (pull_request) Failing after 35s
CI / backup-restore-drill (pull_request) Successful in 36s
CI / web (pull_request) Successful in 32s
KTD1 fifth step (behavior preserved):
- squad.AssetProvider{DocTemplate,RenderDoc,AgentInstruction,
  AgentInstructionFile} injected via Options.Assets into Service,
  WorkspaceEngine and AdaptivePlanner
- bizdev templateAssetProvider maps port to internal/template (assembly side)
- nil-provider paths degrade to the same fallbacks the old error branches
  used (placeholder template, role header) — fail-visible, no guessing
- squad -> template import eliminated; arch edge moved bizdev->template
- verified: build/vet/arch green, squad+bizdev short tests pass
2026-09-29 06:29:51 +00:00
agent-bot 8c2dd49e80 refactor(squad): quote preparation moves to Core via TaskPreparer hook
CI / web (pull_request) Successful in 32s
CI / go-vet (pull_request) Successful in 14s
CI / short-tests-report (pull_request) Failing after 35s
CI / backup-restore-drill (pull_request) Successful in 33s
KTD1 fourth step:
- squad.Options.TaskPreparer + TaskPreparation (Attachment + Backfills +
  MirrorTemplateToOutput); squad stays sole writer of its workspace files
- CDO quote calc/xlsx/backfill implementation moves to bizdev
  (quote_preparer.go); squad/quote_backfill.go relocated to bizdev
- arch path rule enforced the boundary: bizdev may not name/write
  output.md; mirroring decided squad-side via flag
- squad -> quote import eliminated; engine.go delegations now local
- verified: build/vet/arch green, squad+bizdev short tests pass
2026-09-29 06:16:19 +00:00
agent-bot f034a80c09 refactor(squad): drop dead WorkspaceRefForRun adapter (zero callers)
squad -> workspace import eliminated; physical workspace refs stay
product-side per KTD1. Arch edge removed from allowlist.
2026-09-29 06:11:55 +00:00
agent-bot e47cfd8f4e refactor(extract): move text extraction to internal/textextract
CI / go-vet (pull_request) Successful in 12s
CI / short-tests-report (pull_request) Failing after 36s
CI / backup-restore-drill (pull_request) Successful in 24s
CI / web (pull_request) Successful in 32s
KTD1 third step: material parsing returns to its own capability.
- ExtractTextWithAnchors + docx/anchor helpers move from squad/extract.go
  to internal/textextract (pure stdlib, no workflowdef dep)
- squad/extract.go keeps only ExtractAdvisorBriefing (squad domain logic)
- callers updated: squad context builders, bizdev materials, server
  chat_document_reader, materialindex pipeline
- reverse dependency materialindex -> squad eliminated (KTD1 explicit goal)
- module-boundaries.yaml: textextract declared + 4 edges
- verified: build/vet clean, arch green, textextract/squad/materialindex/
  bizdev tests green; server pre-existing env-dependent failure unchanged
  (issue #2, fails with and without this change)
2026-09-29 06:11:20 +00:00
agent-bot 2cd52da85d refactor(squad): typed ProgressSink port replaces direct stream dependency
CI / go-vet (pull_request) Successful in 12s
CI / short-tests-report (pull_request) Failing after 35s
CI / backup-restore-drill (pull_request) Successful in 36s
CI / web (pull_request) Successful in 33s
KTD1 second step (behavior preserved):
- squad defines ProgressSink (EmitPhase/Detail/Deliverable/Summary/Briefing)
  with its own DetailEvent/ToolEvent types; zero internal/stream imports left
- bizdev assembly maps port to SSE streamer (squad_progress_adapter) and
  injects via ctx at the four squad entry points
- process_bridge tests rewritten as port-contract tests (captureSink)
- verified: build+vet clean, squad/bizdev/archtest green
2026-09-29 05:51:32 +00:00
agent-bot 72c0996b74 refactor(squad): inject Options + backend factory, drop config.Config dependency
CI / go-vet (pull_request) Failing after 10s
CI / short-tests-report (pull_request) Failing after 36s
CI / backup-restore-drill (pull_request) Successful in 27s
CI / web (pull_request) Successful in 30s
KTD1 first step (in-repo decoupling, behavior preserved):
- squad.Options{BackendName, BackendTimeout, DataDir, NewBackend} replaces
  *config.Config; defaults applied in withDefaults
- backend construction injected by caller (bizdev assembly): credentials,
  environment and concurrency stay product-side; nil factory fails closed
  instead of silently degrading to Stub
- verified: go vet ./... clean, squad/bizdev short tests pass
2026-09-29 05:09:54 +00:00
weichen 44abb2fa83 merge: candidate intent-material-2026-09-28 into dev 2026-09-28 18:54:32 +00:00
weichen a6a9583b5b merge: candidate controlled-projection-project-binding-2026-09-28 into dev 2026-09-28 17:43:41 +00:00
weichen 4e10d97b5a fix(intent): 资料类提问命中相似案例意图并脱离阶段推销模板 2026-09-28 17:20:25 +00:00
weichen 16f33b5b9d fix(chat): 用本地任务键判断调研前置,避免越界依赖
chat 不能引用 workflowdef。调研报告只认 research 与 bd_research 两个现用键。
2026-09-28 15:44:04 +00:00
weichen 721af4ccb8 fix(squad): 区分未注入对话的原因并附上采集统计
占位说明不再把开关关闭、项目未绑定和本轮没有对话包混成一句,避免把未采集误写成对话已被滤掉。
2026-09-28 15:36:38 +00:00
weichen 54e92c973a fix(chat): 回填会话项目身份并给出阶段前置建议
协调器只解析上下文字符串项目 ID。会话只写数字项目 ID 时,任务项目恒为 0,对话注入和阶段门禁都不会生效。
2026-09-28 15:36:37 +00:00
weichen f8730791b9 fix(coordinator): 回填会话项目绑定,避免受控投影被跳过
聊天入口只把项目 ID 放在授权字段,协调器仍读空的 UserCtx.Project.ID,受控任务因此以 project_id=0 跳过账本投影,回复却称正文已保存。
2026-09-28 12:34:32 +00:00
weichen 5d762fb206 merge: candidate subagent-process-view-impl-2026-09-28 into dev
# Conflicts:
#	.doc/ops/CURRENT.md
2026-09-28 10:36:26 +00:00
weichen 3d6dcc3ae5 feat(web): 用小队子页面展示思考与工具过程
气泡只聚合过程摘要并链到 hash 子页面;成员编制来自只读 squad 端点,思考与工具默认折叠。
2026-09-28 10:30:53 +00:00
weichen 265616e997 feat(stream): 打通小队过程事件到持久化 detail 帧
pi-native 与 runner NDJSON 把推理和工具调用投影为 detail,任务流始终落库;非 200 的流式尝试回落到一次性 /v1/run,避免改变既有错误分类。
2026-09-28 10:30:52 +00:00
weichen a90cce73b9 fix(docgov): 保护共享内存 map,避免并发读写把进程打崩
per-doc 锁只串行同一文档,不同 docID 仍裸读写 memDocs 等 map。GetDocument 与另一文档写入撞上时运行时 fatal,代理把全部 API 变成 500。
2026-09-28 08:52:44 +00:00
weichen f46480a987 feat(workflow): 商务叙事阶段允许编制任意已启用文档 2026-09-28 07:29:59 +00:00
weichen e5c2519fea merge: candidate refresh-task-state-recovery-2026-09-28 into dev 2026-09-28 06:18:08 +00:00
weichen b820e0070d fix(taskrun): 刷新后恢复进行中任务并纠正进度问询
进行中的 run 提前写下消息锚点,并按会话列出活跃任务;进度疑问句改为查询真实状态,交付物已落盘且不是传输失败时不再被空结果否决。
2026-09-28 06:09:42 +00:00
weichen 4bb265b431 merge: dev into quality-gate-heading-mismatch 2026-09-28 05:30:54 +00:00
weichen 4c42d1bf74 merge: candidate agent-reply-llm-narrative-2026-09-28 into dev 2026-09-28 05:13:29 +00:00
weichen aea19f70ef fix(squad): 章节标题归一化后不再把空格和层级漂移判成缺章
聊天触发的任务同时打开质量自动修复,避免格式误报直接阻断受控投影。
2026-09-28 05:12:51 +00:00
weichen 6e1d5830b5 merge: candidate test-user-doc-issues-2026-09-28 into dev 2026-09-28 04:15:18 +00:00
weichen db859e185e fix(intent): 让「帮我定任务书」进入任务并说清失败
写动词补上制定/拟定与祈使「帮我定」,避免落到阶段对照模板。质量未通过不再声称正文已保存到宿主机路径;研发前置未满足时把中文原因直接回复给用户。
2026-09-28 04:01:02 +00:00
weichen d55488ae37 feat(coordinator): 用智能体叙述查询、帮助与操作回执
确定性事实仍由代码生成;PI Agent 只组织语言,失败或关闭开关时回退原模板。安全拦截与确认提问保持模板。
2026-09-28 03:25:06 +00:00
weichen 3ba15df875 fix(agent): 记录 PI runner 数据目录核对结果
启动后第一次核对通过时打一条不含路径的日志,便于确认 test 没有再打到 dev sidecar。
2026-09-28 03:17:26 +00:00
weichen 4f581306d7 fix(agent): 拒绝把工作区发给数据目录不一致的 PI runner
test 启动时根 .env 的 dev runner URL 盖过了 18866,sidecar 把 test 工作区重写到 dev 空目录,模型因读不到材料报 MISSING_TARGET。端口约定优先,并在调用前核对 runner data_dir。
2026-09-28 03:16:27 +00:00
weichen dddd3fe8c8 merge: candidate error-code-observability-2026-09-28 into dev 2026-09-28 02:37:48 +00:00
weichen f3f23a3018 feat(errcode): 用稳定错误码记录 HTTP 与异步失败
失败响应此前不写日志,request_id 无法对照原因。注册表不覆盖处理器已经给出的 HTTP 状态。
2026-09-28 02:27:16 +00:00
weichen 457e870330 fix(chat): 只上传文档时给出梳理或追问,不再裸报 HTTP 400
空消息加附件可以进入回合。无文字时按解析状态引导或回退审阅,有文字但未处理文档时先回答再追问。4xx 信封不再被前端丢弃。
2026-09-28 02:00:24 +00:00
weichen c713834954 fix(bizdev): commit squad ledger as the document author
Non-author triggers were denied by dutyAuthorizer because AutoCommitUserID was the triggering user. Record that user on OnBehalfOf and surface the duty mismatch in the task error.
2026-09-28 01:24:25 +00:00
weichen 88b7c11a23 fix(auth): reseed standard roles and reject duplicate usernames as 400
Registration always writes role-guest; a deleted standard role became a masked INTERNAL. Username unique violations are now a 400 instead of an infrastructure 500.
2026-09-28 01:12:07 +00:00
weichen 88e33282db fix(freedoc): persist uploaded file metadata and text body server-side
上传文档跨端不可访问修复(ISSUE-20260927-upload-doc-cross-device):
- 迁移 00076:freeform_documents 增加 source_filename/mime/size_bytes/asset_id
- freedoc:Create/Get/List 读写源文件元数据,负值拒绝
- 前端:注册前全部附件先登记 CAS 并预读文本正文;文本正文嵌入注册
  markdown;跨端恢复 sourceType/fileMeta 路由回文件预览器
- 大小显示 formatFileSize(<512B 不再显示 0 KB)
- E2E 新增 FS-UPLOAD-02 跨浏览器上下文可访问性用例

回归:go vet/arch-check/go test -short(隔离 PG)+ web npm test/build 全绿;
存量无元数据旧文档不可恢复(重新上传即可)。
2026-09-27 07:45:15 +00:00
weichen d537778b60 fix(sysadmin): refresh feature maturity catalog to post-rollout wiring facts
The static adapter catalog still read I2-era states (degraded/shadow) after
the 2026-09-26 dev rollout, so the admin features page showed 降级 for flags
already enabled. Update six entries to live+ready with evidence-dated
reasons (I2/I3/P8 acceptance, P8 per-key gates kept visible, shadow
visibility digest now persisted, REPLACE wildcard wiring, PI narrative dev
rollout); keep FAV red lines untouched. Tests updated; FAV now carries the
configured-value-must-not-imply-readiness assertion.
2026-09-26 02:45:05 +00:00
weichen e9c0281404 feat(ctxmgr): wildcard session allowlist for semantic replace rollout
- SEMANTIC_SUMMARY_REPLACE_SESSIONS supports * (all sessions, present and
  future), mirroring INTENT_PLAN_PROJECT_ALLOWLIST; empty allowlist still
  replaces nothing (fail-closed defense in depth unchanged)
- declare SEMANTIC_SUMMARY_REPLACE(_SESSIONS) in dev/test/main compose app
  env (stale Wave2 "REPLACE unwired" comment fixed); extend A-4 declaration
  test; .env.example key docs updated
- sysadmin feature catalog: SESSIONS description + REPLACE reason note *

Prepares dev degraded-flags enable (task degraded-flags-enable-2026-09-26-r4):
user-authorized all-session replace, plan tier confirm, shadow summary, PI
change-report narrative; env ops and runtime verification follow.
2026-09-26 02:29:29 +00:00
weichen 6a3a0dc201 fix(security): harden bypass authz, gate blind spot, command exec, validated_only (review P0/P1)
- FIND-SEC-01: GetUserContext requires session ownership (handler 403 +
  SQL/memory owner filter); in-memory HTTP + isolated-PG regressions
- FIND-ARCH-01: archtest fails closed on untracked table writes (+noise
  exemption) and registers 50 existing writer tables in table_owners
- FIND-SEC-02: Authorizer without pool denies by default; explicit
  NewInMemoryAuthorizer seam opt-in via ALLOW_IN_MEMORY at composition
- FIND-SEC-03: swboot commands run argv-exec (no sh -c) with exact
  basename allowlist match; prefix-spoof and no-shell-eval tests
- FIND-FLOW-01: confirm rejects validated_only plans; ExecuteClaimed
  hard-refuses validated_only steps (new error codes + HTTP mapping)
- FIND-QUAL-01: intentflow.ValidateFlagConsistency fail-fast at Assemble
2026-09-26 02:00:14 +00:00
weichen a52816299d fix(server): read bound repo from project_source_bindings.source_ref 2026-09-26 01:00:37 +00:00
weichen f394bb15f9 fix(projectworkflow): write repo binding into project_source_bindings.source_ref 2026-09-26 00:59:08 +00:00
weichen 83561682eb feat(swboot): wire SWBOOT-10 controlled patch executor (fail-closed)
DB-backed repo_path_allowlist reader (deny-all until admin seeds), per-prefix
admin test_commands (goose 00075), execution evidence table (goose 00074),
isolated git-worktree patch executor with command allowlist/time/output caps
and failure-stops evidence; controlled_patch creation/preview unlocked only
with an allowlisted repo binding (projectworkflow gate + catalog flag);
creator-only server endpoints for bindings/executions; merge/push/deploy stay
behind a typed separate-authorization boundary. Module boundary: app->swboot
composition import registered.
2026-09-26 00:56:59 +00:00