Skip to content

release: promote dev to main (memory L1, subagent role routing, CI and release hardening) - #145

Merged
lidge-jun merged 156 commits into
mainfrom
dev
Sep 11, 2026
Merged

lidge-jun merged 156 commits into
mainfrom
dev

Conversation

@lidge-jun

Copy link
Copy Markdown
Owner

Promotes the current dev head to main. 108 non-merge commits, 476 files, since the last promotion (#89).

What ships

Evidence

CI on a267b398 is green on the full matrix: ubuntu, macOS, and both Windows shards with and without the alternate flag, plus the aggregate ci check and the packed-install lifecycle on all three platforms. The two WSL jobs were still running when this PR was opened and are expected to report on the PR head.

Not included

The Windows issue sweep currently in flight (issues #109, #131, #132, #133, #134) is a separate stacked chain based on this dev head and will be promoted after it lands.

Risk

This is a promotion of an already-integrated dev, not new work. Every constituent change was reviewed and merged with its own green CI. The promotion itself introduces no diff beyond the union of those merges.

lidge-jun and others added 30 commits September 8, 2026 13:03
docs: archive the 0.2.24 delivery unit (reader documents, deep research, PR #84)
…sion

test: cover Windows short-path source bindings
Resolves the README test-count badge conflict from #92 (2,671) against this
branch's 2,692, then re-measures the merged suite: 2,697 total.

Also fixes two MAJOR defects found by independent review of the effort/model
capability interlock. reasoningEfforts() is three-state - an array is the
model's advertised ladder, null means the source did not advertise one - but
the dashboard folded null into [] with '?? []', so every effort option was
disabled for a model whose ladder OCX does not report, and a saved effort made
those models unselectable with a misleading error. Live rosters carry that
state, so this is reachable, not hypothetical.

- extract effortExcluded() into gui/src/effort-support.ts, which returns true
  only for an actual array that omits the effort
- use it at the option-disable, the save guard and the unsupported warning
- add gui/test/effort-support.test.ts pinning all three states

Verified: 2,697 tests pass, gui tsc --noEmit clean, inventory and gate OK.
fix(subagents): persist effort and add global defaults with live OCX models
The plugin cache was registered as a git-source marketplace pinned to a commit,
so the installed payload was a snapshot of main rather than the dev checkout.
scripts/dev-symlink.sh was meant to bridge that gap by symlinking each cache
child back into the repo, but Codex does not resolve those entries reliably and
the plugin can silently fail to load. The script had also drifted: it hardcoded
VERSION="0.1.0" while the live cache directory is 0.2.24+codex.20260908031619.

Replace it with scripts/dev-install.sh, which installs the checkout as a real
copy from a local marketplace. codex plugin add re-copies the payload and prunes
files that no longer exist in the source, so a same-version reinstall is a true
resync and re-running the script is the whole update loop.

- document the flow in all three READMEs: why symlinks were retired, local vs
  git marketplace, real-copy and prune semantics, the --status/--no-build flags,
  the edit/reinstall/new-thread loop, content-hashed hook trust, and the
  diff -rq / find -type l / cxc doctor verification triple
- fix a prose defect the badge sync cannot see: README.ko.md and README.zh.md
  said 22 hooks while the badge and architecture block said 23; the manifest
  ships 23
- extract marketplace_root() in dev-install.sh so a checkout path containing a
  space is not truncated at both call sites
- rename the docs-site page to dogfood-dev-install and update its inbound links

Verified: 2,697 tests pass, npm run gate OK, badge sync clean, bash -n and a
live --status run.
An independent audit of 9479f77 found three MAJOR inaccuracies, each verified
against the implementation before fixing.

Hook trust is not a hash of file bytes. identityHash canonicalizes the hook
DECLARATION - event, matcher, command, timeout, async, statusMessage - at
hook-trust.ts:117-131. The practical consequence is the opposite of what the
text implied: rebuilding a component dist/ changes many cached bytes and keeps
trust, while editing a matcher in hooks/*.json breaks it.

'expect: overall: PASS' was wrong in exactly the case the paragraph above it
warns about. rollup() returns FAIL if any check fails (doctor.ts:65-71), and
hook-trust fails whenever a hash is untrusted, so a reader awaiting re-approval
sees FAIL with no way to distinguish it from a broken install.

The quickstart led with a manual 'codex plugin marketplace add', which aborts
for anyone already on the published track since the name collides with the git
marketplace. dev-install.sh already repoints correctly on its own, so the
manual step was both unnecessary and the one that errors.

Also fixes the symlink cleanup description (the script clears the whole cache
directory, not individual links), a Korean particle, and the missing 'expect'
framing in the Korean verification comment.

Verified: npm run gate OK, badge sync clean.
…r; register swarm-era rule IDs

branch-lifecycle.md §2 listed 8 keep rules while the OpenCodex closed-PR planner
(closed-pr-branch-cleanup.cjs) evaluates 10 keep reasons plus one out-of-scope skip.
The missing outcomes (outside-disposable-namespace, unknown-head-sha,
branch-moved-since-close) came from lidge-jun/opencodex 59d9bc95f, which stopped the
planner deleting a branch whose name had been reused for new work. The table now
matches the planner in evaluation order, quotes the tip-SHA check, and states that
under squash/rebase merging PR state, not ancestry, is merge truth.

SKILL.md §2.9 registers DEVOPS-BRANCH-NAMESPACE-01, DEVOPS-REPO-BOOTSTRAP-01,
DEVOPS-AGENT-INTAKE-01 and DEVOPS-LOCAL-GC-01; the owner references for the last three
arrive in the following layers of this chain, which add their own Modular References
rows.
…nt-facing repositories)

The skill could read delete_branch_on_merge but never said how to set up a repository
so it stays clean. repo-bootstrap.md gives the dev/preview/main model, ruleset JSON for
integration lines and release tags, the gh api PATCH for merge settings, the closed-PR
cleanup job values, GitHub pull request limits (drafts exempt), a minimum label set with
the bait-label warning, a read-only bootstrap check table, and anti-patterns observed on
the four lidge-jun repositories on 2026-09-09. Reference-local sub-rules
DEVOPS-RULESET-FIRST-01, DEVOPS-MERGE-SETTINGS-01 and DEVOPS-PR-LIMITS-01 sit under
DEVOPS-REPO-BOOTSTRAP-01 (registered in L1). Adds the Modular References row.

Plan folds from the A-phase audit are recorded in 020_l2_repo_bootstrap.md.
…ersede, three policy strengths)

No skill file addressed the volume of agent-authored pull requests. agent-pr-intake.md
starts from the economics three projects state independently (review, not authorship,
is the scarce resource), defines three identity tiers and an agent convention table for
Copilot cloud agent, Codex cloud and Claude Code Actions, sets draft-first as the default,
gives a six-step supersede procedure tied to branch-lifecycle keep rules 8-10, and lays
out weak/medium/strong intake policies as options with the project that used each value
(OpenSSL, llama.cpp, Godot, dotnet/runtime, Kubernetes, LLVM, ghostty, Crossplane).
The four unresolved practitioner disagreements are recorded rather than decided.
Reference-local sub-rules DEVOPS-AGENT-IDENTITY-01, DEVOPS-DRAFT-FIRST-01 and
DEVOPS-PR-SUPERSEDE-01 sit under DEVOPS-AGENT-INTAKE-01 (registered in L1). Adds the
Modular References row.

Audit folds are recorded in 030_l3_agent_pr_intake.md.
…ss-skill pointers, changelog

Local worktree and branch state is invisible to GitHub Actions, and the 2026-09-09
inventory found 133 worktrees and 530 local branches across four repositories with no
GC command and no schedule. local-gc.md sets the conventions an automated cleanup must
follow: PR state as merge truth, candidate classes with a base-of-open-PR guard and the
planner grace period, worktree exclusions (active session, managed slots, locked, dirty,
unreferenced detached), config hygiene, dry-run-only scheduling, and the contract a
future cxc worktree gc must satisfy (marked not implemented).

Pointers: worktree-guardian §4, stacked-prs DEV-STACK-04 supersede bullet,
agent-infra-safety intake note, ci-cd-deploy anti-pattern rows, skill-ownership rows for
the three new owner files. CHANGELOG Unreleased entry and compare-link retarget.

Audit folds are recorded in 040_l4_local_gc_pointers_changelog.md.
…race constant and a distinct partial-completion exit code (review nits)
lidge-jun and others added 25 commits September 10, 2026 07:55
…iff-level decade docs for wp1–wp6

Records the 2026-09-10 diagnosis of the post-L0 memory issues (two real
regressions: #102 gate false positives, #105 version-string boundary), the
Tier-2-verified web survey of agent memory harnesses, and diff-level plans
for six implementation work-phases. Audited in three rounds by an
independent reviewer (final: PASS). No code changes.
docs(plan): memory-followup L1 roadmap, web survey, and decade docs
…destination

The gate denied read-only sed, 2>/dev/null redirects, and any command whose
body mentioned the memories path (a devlog heredoc quoting it was blocked
four times in one session). Replace the body-token scan with a destination
parser: stdout redirections (including no-space > / >> and >| clobber), tee,
sed -i, cp/mv targets, perl -i / ruby -i operands. Heredoc bodies, quoted
text, stderr redirects, and read operands are never destinations.

Tool-name and apply_patch/Write/Edit legs are unchanged. Early warning, not
enforcement: subshells, expansions, python -c and 'echo hi -> P' remain
named bypasses (plan 010 §8).
fix(pabcd-state): classify memory-write gate shell commands by write destination
…e boundary groups that missed

"2.49.0" matched the FILENAME rule (its ".0" looked like an extension) and was
boundary-gated, so a corpus that writes "v2.49.0" never matched: the "v" is a
token character. Classify dotted versions (optional v prefix) as VERSION and
accept a lone token-edge "v" before a version core as a boundary.

The zero-result retry used to drop boundary gating on every group. It now
tallies which groups occur anywhere in the corpus (markdown files plus
stage1_outputs) and relaxes only the boundary groups absent everywhere, so a
group that does hit on boundaries (c-4: "LSP" vs NaiControlsPanel) keeps its
precision when a sibling group misses.

Golden: memory search "2.49.0 SLSA" recovers the MEMORY.md chunks with no
relax warning; "LSP" output is byte-identical to the previous build.
fix(recall): treat dotted versions as VERSION words and relax only the boundary groups that missed
… query ladder

The skill claimed things the CLI does not do ("an empty answer is never the
outcome", trigram FTS on both engines, one JSON schema, "never modifies
anything") and listed fewer flags than the USAGE text. It also had no
procedure for the case that fails most: a natural-language sentence that
returns 0 hits while its keywords hit.

Rewrite: synopsis equals cli.ts USAGE (pinned by a new test), the two engines
are described separately (chat: substring AND, trigram index, BM25+RRF
ranking; memory: paragraph scan, Korean stems and synonyms, boundary-gated
symbols including dotted versions, per-group relaxed retry), a natural
language to keyword ladder, result checks (request vs completion, version
strings are not release evidence, later corrections), subagent --source,
managed-worktree --cwd guidance (until wp4), native memories.* vs cxc, and
optional Aside / wiki lanes gated on the tool being installed.

docs-site: hook counts to 28 files / 29 handlers with the bg-wake and fallback
rows, --rank and allow-write in the command reference, memories.dedicated_tools
no longer listed as a future surface.
docs(recall): rewrite the cxc-recall skill to match the CLI and add a query ladder
…orktrees join their main checkout

--cwd / --cwd-only matched on a cwd path prefix, so a session in a managed
worktree (~/.codex/worktrees/<slot>/<repo>; 23.5% of all sessions, 43.6% for
opencodex) was scoped as a different project from its main checkout and the
SessionStart recall hook injected nothing for a fresh slot.

Add repo_key: the normalized git remote (scp/ssh/https/git collapse onto
host/owner/name, .git and trailing slash dropped, host lower-cased, path case
kept). It is parsed from session_meta payload.git.repository_url at ingest,
joined from threads.git_origin_url for older rows, and stored as a nullable
files.repo_key column added with a PRAGMA-guarded ALTER (schema version
stays "2"; a lazy 1,000-row backfill runs outside the per-file transaction,
so an installed 0.2.24 CLI can keep using the same index). memory search
scopeAdjust, the chat index WHERE, the JSONL scan filter and the hook's
listCwdSessions all accept a same-origin hit as a scope hit; a missing origin
falls back to the cwd prefix. cwdMatches folds case on darwin.

Golden (live index, read-only): memory search "메모리" --cwd-only <worktree>
went from 0 memory artifacts to 7, three recorded under the main checkout,
with no cli-jaw/opencodex hits. On an APFS clone of the 12GB index one
refreshing query filled repo_key on 10,875 of 13,247 files without dropping
or re-parsing messages.

The recall skill's temporary "until wp4" paragraph is replaced.
feat(recall): key project scope by normalized git origin so managed worktrees join their main checkout
…ional match plan

A query longer than eight words was silently truncated and every remaining
word had to match with AND, so the sentences people actually type ("지난번
로컬 소스를 실제 서비스에 연결하고 정상 동작까지 확인한 방법") returned nothing
while their keywords hit.

Compile every query into one MatchPlan shared by the chat index, the chat
JSONL scan and memory search: nine words or more keep symbols, versions and
proper nouns as required AND terms and let the rest match by a ceil(n/2)
quota; eight words or fewer keep the old all-AND behaviour. A minimal
stopword list (그/이/저/것/문제/방법) applies at any length. The plan is the
final predicate at all three index sites (relevance recheck, top-up sweep,
recent row filter), so index and scan stay equivalent; recent fetches a
larger pool before the predicate and cuts at limit+1. Memory recompiles the
plan inside collect() so the per-group relaxed retry from #125 still runs.

chat search gains --synonyms (default off) to apply the Korean stem and
synonym expansion memory already uses. Synonym seeds for 도그푸딩/재시작/
검증/소스/플러그인 and the 인지 ending are added.

Golden set: a synthetic corpus pins D3/P2/R2 with n>=1 on chat and memory,
the LSP and Korean-stem regressions, and index/scan parity for required=0
and required>=1 nine-word oracles in both modes. Live index (read-only):
D3 chat 0 -> 2 hits and 7.3s -> 0.75s; D3 memory 0 -> 3; P2 chat 0 -> 3
with --synonyms.
feat(recall): relax long natural-language queries with a required/optional match plan
…reshness labels, hook output contract

Four native-integration items from the 2026-09-10 web survey (claude-mem hook
lifecycle, Claude Code SessionStart source field, arXiv 2608.15008 on
over-retrieval):

- SessionStart shapes its notice by source (startup/clear, resume, compact)
  and ends every shape with one capped recovery line: memories.search when
  config.toml has [memories] dedicated_tools = true (read through codexHome(),
  fail-open false), otherwise the cxc chat/memory search commands. Budgets
  and the repo-key project block from #127 are unchanged.
- UserPromptSubmit appends "Suggested recall terms: ..." when recall intent
  fires, extracted from the prompt (versions, filenames, error codes,
  CamelCase, quoted spans; max 4). No search runs in the hook; extraction on
  an 8,000-char prompt stays under 20 ms. Five trigger idioms added; bare
  "그때" stays out.
- memory search text output labels each hit [age: Nd] and marks a hit whose
  distinctive tokens also appear in a newer hit in another file with
  [newer: <relpath>]. Ranking is untouched.
- Hook output contract: assertLegalHookResult({stdout, stderr, code}) is
  pinned by a child-process test over dist/cli.js hook <event> with an empty
  temp CODEX_HOME (exit 0, no ANSI on stderr, stdout empty or a JSON object).
  cxc doctor reports trusted_hash drift as WARN with file_sha256 evidence;
  a missing trust entry stays FAIL.
feat(recall): source-aware session briefing, targeted recall hints, freshness labels, hook output contract
* fix(subagents): preserve explorer routing across native input forms

* docs: record explorer routing tests and native delivery evidence

* docs: link evidence to the publishable implementation commit

* docs(agents): decide discovery ownership before broad reads

* fix(agents): clarify dispatch reports and bounded verification

* build(subagents): refresh dispatch guidance artifact

* docs: record discovery behavior and local verification evidence

* fix(subagents): bound items expansion and dispatch authority

* fix(subagents): require exact coordinator grant wrappers

* fix(pabcd): retain reviewer routing in recovery instructions

* fix(pabcd): support reviewer advice without a role field

* docs: record spawn payload repair and installed verification
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 11, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-11T10:30:54.844153Z a267b39 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a267b3981f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +126 to +130
await github.rest.git.deleteRef({
owner,
repo,
ref: `heads/${entry.branch}`,
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Recheck the ref tip immediately before deleting

In the scheduled cleanup workflow, if someone pushes new work to an eligible codex/* branch after listBranches captures its SHA but before this call executes, deleteRef receives only the branch name and deletes the now-moved ref unconditionally. The 404/422 handler does not protect this race because no expected SHA is supplied or checked at deletion time; refetch and compare the tip immediately before deletion so concurrent pushes cannot be destroyed.

Useful? React with 👍 / 👎.

Comment on lines +240 to +244
if (!isTerminal(rec.status)) continue;
if (rec.deliveredAt !== null) continue;
if (rec.sessionId === sessionId || rec.adoptedBy === sessionId) continue;
const next: BgRecord = { ...rec, adoptedBy: sessionId };
writeRecord(next);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid adopting completions from another live session

When two Codex sessions are open in the same cwd, starting the second session adopts every undelivered terminal record owned by the first, even though the first session may still be active and waiting to consume it. This both routes background output to the wrong thread and prevents the registering thread from receiving its own completion; adoption needs evidence that the original session is gone, or an explicit handoff mechanism, rather than treating every different session ID as orphaned.

Useful? React with 👍 / 👎.

Comment on lines +516 to +518
const chatHits = localChat.hits.filter((hit) =>
cwdMatches(hit.cwd ?? "", cwd, { caseInsensitive: FOLD_CWD_CASE }),
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve same-origin hits in the fallback path

When the sidecar index cannot be opened, buildCwdContext falls back to searchChat, which now scopes results by either cwd prefix or matching git origin. This second filter then retains only cwd-prefix matches, discarding sessions from the main checkout when the current cwd is a managed worktree with the same origin. Consequently the advertised cross-checkout recall works only while the index path is available; the fallback must retain the same-origin results already accepted by searchChat.

Useful? React with 👍 / 👎.

@lidge-jun
lidge-jun merged commit 6aae1c9 into main Sep 11, 2026
27 checks passed
@lidge-jun
lidge-jun deleted the dev branch September 11, 2026 10:38
@lidge-jun
lidge-jun restored the dev branch September 11, 2026 11:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants