Skip to content

Merge upstream main for opt-in Jev dispatch - #27

Merged
rega10 merged 13 commits into
mainfrom
fm/firstmate-fork-sync-upstream-jev-dispatch
Sep 17, 2026
Merged

rega10 merged 13 commits into
mainfrom
fm/firstmate-fork-sync-upstream-jev-dispatch

Conversation

@rega10

@rega10 rega10 commented Sep 17, 2026 •

Copy link
Copy Markdown
Owner

Merge upstream Firstmate through fa93097162d16f70a070044b8ccece037a38e3e6 into the fork to make opt-in Jev dispatch resolution available while preserving the fork's integrations.
The fork parent is bd00258d1c3c9db5ca99793d63517e9e47efe296.
This brings in 11 upstream commits while retaining the 25 fork-only commits and their history.
Use a merge commit when landing so future synchronizations retain upstream ancestry.

The upstream tip contains 69d660ad6167271daf09e8c5521581c03cb9a4f8, the merged typed dispatch implementation, including bin/fm-dispatch-resolve.sh, tests/fm-dispatch-resolve.test.sh, and docs/verification/dispatch-resolve.md.
The preservation precedent is the previous fork synchronization.
No real API key, running-home configuration, benchmark, or authenticated Jev request is involved in this change.

Fork-only commit classification

Classification is against the exact upstream tip above, based on git log upstream/main..origin/main, the patches, the previous synchronization's preservation record, and the remaining fork-versus-upstream diff.
No fork-only commit is an exact already-upstreamed patch (git cherry finds no equivalent patches).
The Pi renderer change below is superseded in behavior; its separate cleanup safeguard remains.

Fork commit Classification Disposition
4c8d97bd cmux failed-list guard Still needed Preserve refusal on failed or empty pane listings in fm_backend_cmux_surface_exists.
e31fd313 review-diff branch resolution Still needed Preserve actual task-worktree HEAD branch selection instead of preferring fm/<id>.
8d304c6c Herdr capability probe Still needed Preserve in-process schema matching and the large-schema regression.
259be8e0 Claude session identity Still needed Preserve inherited Claude session-identity scrubbing during worker launch.
105ff038 hosted Codex locks Still needed Preserve opaque codex:<thread-id> ownership and conservative reclamation alongside numeric owners.
ae77b98d legacy Herdr binding repair Still needed Preserve guarded bind-only repair and the shared fm-work-landed-lib.sh reachability predicates.
045e5382 tasks-axi compatibility gates Still needed Preserve compatibility checks in both handoff suites.
d0f820d7 Bitwarden migration tooling Still needed Preserve ceremony validation, record I/O, tests, and operator documentation.
30705e93 Bitwarden rotation boundary Still needed Preserve the migration-versus-rotation scope boundary.
1af5ea04 Automic Vault worker authentication Still needed Preserve opt-in injection, qualification, redaction, local inheritance, and remote exclusion.
3294f656 Vault development-only boundary Still needed Preserve synthetic validation and the prohibition on automated real credential provisioning.
c3b6535b project lifecycle registry Still needed Preserve the canonical posture writer/parser and lifecycle projection owner.
e353d9bd sole Vault settings Still needed Preserve the sole credential-scrubbing Claude settings object and no-fallback behavior.
160c812b Vault settings invariant documentation Still needed Preserve the settings owner and safety invariant.
20240d73 Vault verification documentation Still needed Preserve the executable verification pointers.
71522695 Vault filtering regression Still needed Preserve split/equals settings filtering and permission-mode coverage.
663a5f68 Herdr/Vault verification consolidation Still needed Preserve the distinct fork repair and Vault verification records.
99839a98 Bearings versioned contract Still needed Preserve --contract; declare the new upstream contribution surface so the contract remains accurate.
cdd5462a Pi renderer baseline Superseded The previous sync adopted upstream's newer stock-tool factories and renderer guard; keep that result and the independent failed-watcher-fixture cleanup.
0a14719c Orchestra live-board refresh Still needed Preserve detached refresh on actionable watcher exits and heartbeats.
f50a7997 lifecycle across Bearings projections Still needed Preserve parked/archived filtering, project identity, ordering, and bounded secondmate lifecycle inventories alongside upstream contributions.
4c06f118 prior upstream integration merge Still needed Retain its ancestry and reconciled fork behavior, including socket spelling versus lock identity and the split landed-work owners.
67b3e863 previous pipeline integration fixes Still needed Preserve namespace-PID-1 lock acceptance, cached Bearings vocabulary, and removal of a source-text-only test.
46d09085 changed-test asset mapping Still needed Preserve consumer-suite selection for executable browser assets and its regression.
bd00258d prior synchronization landing merge Still needed Preserve the fork's published merge history and upstream ancestry.

Exact conflict inventory

Conflicted file Resolution
bin/fm-bearings-snapshot.sh Keep upstream contribution aggregation and the fork's top-level projects array together.
bin/fm-fleet-snapshot.sh Keep both help contracts; load upstream contribution data into the fork's lifecycle-aware secondmate summary without replacing normalized project/task bindings. Preserve both contribution and lifecycle fields in the resulting snapshots.
bin/fm-test-run.sh Union upstream contribution test selection with the fork lifecycle mappings and preserve the separate project-posture mapping.

AGENTS.md merged automatically without manual edits.
The required fm-ensure-agents-md.sh . helper reported it unchanged.
The upstream resolver, its fixture suite, and its verification record remain byte-identical to the fetched upstream tip.

Three integration corrections supplement the conflict resolutions:

  • Apply the fork lifecycle contract to contribution-call presentation: archived calls are suppressed, parked calls remain represented in Charted Next, and dated parks resurface on expiry. Coverage totals, actor counts, storage, and polling stay unchanged; lifecycle_suppressed and an explicit omission line disclose suppressed calls. Secondmate summaries carry their owning project identity, and older summaries without enough identity retain their calls rather than guessing from the parent registry. This is a fork presentation adaptation, with no change to upstream contribution storage or polling.
  • Declare the upstream contributions object in the fork's machine-readable Bearings contract. The executable snapshot previously emitted an undeclared surface; the existing contract regression guards this boundary.
  • Add three completed fork-only suite timings from green CI run 35052209884. Each parent passes the coverage guard separately, but their combined inventory initially had 28 unmeasured serial suites out of 180, exceeding its unchanged 15% limit. Recorded timings for Bitwarden ceremony (19806 ms), Vault (37724 ms), and Claude session environment (69 ms) reduce that count to 25; these are measured hints, not fabricated durations or relaxed limits.

Enable the resolver after landing

The operator contract is docs/configuration.md, Typed dispatch resolution (.env TYPESAFE_API_KEY).
After the running home has adopted this merge, the owner can privately add a nonempty TYPESAFE_API_KEY=<owner-supplied key> line to /Users/rega1011/Projects/firstmate/.env, retaining existing entries, and set that file to owner-only read/write mode with chmod 600 /Users/rega1011/Projects/firstmate/.env.
Mode 600 is the recommended secret-file permission, not an activation condition enforced by the resolver.
Alternatively, supply the variable in the firstmate process environment; a nonempty environment value takes precedence.
No additional enable flag is needed.
The resolver reads the home-local key on each invocation, and updated AGENTS.md directs firstmate to invoke it immediately after writing a task brief.
The key is not propagated automatically to other homes by this merge.

Without a key, the tool prints dispatch-resolve: off on stderr, emits nothing on stdout, exits 0, and makes no request.
Only clear emits a spawn profile; off, ambiguous, escalation, and error outcomes return to the existing intake.
An existing malformed configuration remains an actionable exit 2.
The tool does not replace firstmate's catalog/authentication, reasoning-class, completion-runway, or approval judgment.

Existing crew-dispatch.json migration checklist

docs/configuration.md, Crew dispatch profiles owns the schema.
There is no schema-version bump and single-profile objects remain supported.
These changes apply when typed resolution is opted in; without a key the new declarations remain inert.

Field or constraint Required review of existing rules
Profile provider, in both rule use and top-level default Explicitly declare the exact quota-axi provider ID for pi, pi-signed, omp, opencode, gemini, and rovo; omission is an error before any request. The single-provider defaults are claude -> claude, codex -> codex, grok -> grok, kimi -> kimi, cursor -> cursor, agy -> agy, and muse -> meta. Explicit IDs must match ^[a-z0-9]+(-[a-z0-9]+)*\z. Do not infer a multi-provider model's family from its harness.
Rule approval Optional; the only accepted value is "captain". Declare it for rules requiring approval so the tool escalates instead of emitting a profile. Approval prose in when or why alone is not an executable gate.
Rule floor Optional object with provider, nonempty scope, and numeric min_percent from 0 through 100. A known shortfall falls back to default; missing/unknown evidence escalates.
Profile floor Optional object with nonempty scope and numeric min_percent from 0 through 100. It must not contain provider; it uses the profile provider. A known shortfall excludes the candidate, and unknown evidence makes it unrankable.
Duplicate profiles Within each use or default array, duplicate (harness, model, effort) tuples are errors, even if provider or floor declarations differ.
Existing shape and effort constraints Keep nonempty when, nonempty use, valid verified harnesses, and model/effort strings supported by that harness/model. If select is present it must be "quota-balanced"; no new selection modes are added. Typed mode additionally recognizes gemini, with explicit provider.
Default-only rules files Allowed, but absent/empty rules yields escalate: no rules to match without a model/quota request; ordinary intake selects the default. A missing optional file behaves the same, while malformed/unreadable files and broken symlinks error.

Natural-language match conditions and exemptions stay in when.
The model sees those conditions, the brief, and the project name; it does not see why, use, quota, or approval declarations.
The live rules file was not inspected or changed during this synchronization.

Post-merge verification

Before relying on typed dispatch, firstmate will exercise authenticated resolution in the running home with the owner's real key after merge, including a clear concrete harness/model/effort result and the never-auto-dispatch guards for low confidence, required approval, and quota restrictions.
This synchronization deliberately leaves those authenticated scenarios untested: it cannot read or use the real key.
The upstream fixture suite covers those guards, and direct isolated CLI checks demonstrated the absent-key and no-rules fallbacks.
Firstmate accepted no-mistakes finding test-2 with that verification boundary; no live credential test was attempted to clear the gate.

Noted upstream follow-ups

  • local-secondmate-pending-cleanup-after-home-removal (bin/fm-teardown.sh:3409, severity error): local secondmate retirement removes its home before deleting pending-reply records, so a subsequent cleanup failure can retain a route to a missing home. The review proposed transactional staging with restore-on-failure. Firstmate confirmed this ordering is byte-equivalent upstream behavior, not introduced by this merge; the fix is deferred because changing upstream behavior is outside this synchronization. The completed review was accepted without applying that finding.

Validation

  • All 42 selected portable suites have successful final per-suite verdicts: 39 passed in the initial run, and the test-runner, Bearings snapshot (81 cases), and contribution suites passed the focused corrective rerun.
  • The initial runner completed all 42 suites but lost its final aggregate because its source was edited while it was executing; the focused rerun used the stable final runner and produced a clean JSON result.
  • Full CI=true bin/fm-lint.sh passed with ShellCheck 0.11.0 and actionlint 1.7.12; final local lint, stock Bash syntax, documentation audience/link validation, shard coverage, and git diff --check passed.
  • The coverage guard passes on both parent snapshots and on the merge: 221 suites, including 180 portable serial suites with 25 unhinted durations.
  • fm-session-start.sh --help, fm-spawn.sh --help, and fm-dispatch-resolve.sh --help passed.
  • The upstream resolver fixture suite passed, and an isolated no-key invocation returned exit 0, empty stdout, and dispatch-resolve: off on stderr.
  • Existing optional tmux cases skipped because tmux is unavailable locally; no local real Herdr lifecycle, credential provisioning, authenticated model request, or benchmark was run. The hosted isolated Herdr CI lane passed separately.
  • Parent CI evidence is not uniformly green: the fork-parent run passed 12 jobs with portable serial shard 1 cancelled; the upstream-parent run passed 12 jobs and failed fm-pi-branch-extension.test.sh in serial shard 3 at the sequence-bound acknowledgement case (no durable outcome for claimed wake rows). Merge CI must independently pass; neither baseline is represented as a complete green run.
  • No-mistakes review, test, document, and lint completed. The document step corrected an inherited overstatement in .agents/skills/quota-array-dispatch/SKILL.md: it now points to the resolver-owned gates and limits rather than claiming that the resolver implements every skill gate. Final head is a9c053ffc423015b8178419120f42f0db331b490; all hosted CI jobs passed in run 35198243559, and no-mistakes returned checks-passed.

The hosted portable timing aggregate records 204 scripts, zero failures, and 34 explicit optional-platform or opt-in skips.
The resolver, contribution, Bearings, and Pi branch extension suites all passed without gate skips; the Pi branch extension test that failed on the upstream parent passed on this merge.
The separate required Herdr lane, both parallel lanes, all five serial lanes, lint, invariants, coverage, macOS Bash compatibility, and timing aggregation are green.


The generated pipeline report follows unchanged, including its original risk assessment.
The decisions in "Noted upstream follow-ups" and "Post-merge verification" above explain the accepted findings and their scope.

Intent

Instruction of 2026-09-17: "i'd like to implement Jev for model selection as described by kunchenguid in this X post: https://x.com/kunchenguid/status/2100477276945367454?s=20 I already have an API key for Jev, can you help me set this up?"

Context needed to read that ask: the capability described is upstream kunchenguid/firstmate pull request 4692, "feat(bin): add opt-in typed dispatch resolution", merged to upstream main on 2026-09-17. It adds bin/fm-dispatch-resolve.sh, which takes a written task brief, asks typesafe.ai's System One model (Jev) one Choice question over the natural-language rules in config/crew-dispatch.json, then applies a confidence floor, approval and quota gates, and one quota-axi spendPriority ranking to print the concrete harness, model and effort for the spawn. It is opt-in: it activates only when TYPESAFE_API_KEY is present in the environment or in the firstmate home's gitignored .env, and firstmate routes exactly as today when the key is absent or the result is not clear. This fork (origin = https://github.com/rega10/firstmate, the running Firstmate) is 11 commits behind upstream main and 25 ahead, so the capability arrives by bringing the fork up to date with upstream main while keeping the fork's own integrations working. The API key itself is the fork owner's to place and is not part of this task.

What Changed

  • Add opt-in TypeSafe System One (Jev) dispatch resolution through TYPESAFE_API_KEY, with confidence, approval, quota, and spend-priority gates plus fallback to existing routing.
  • Add durable tracking and Bearings visibility for owned GitHub contributions, preserving observations when polling exhausts its time budget.
  • Sync upstream reliability fixes for status decisions, Codex worker launches, Calm responses, PR polling, remote reports, Orca teardown, and secondmate reply cleanup.

Risk Assessment

🚨 High: The update is otherwise well-bounded, but the new cleanup ordering introduces a destructive, source-verifiable failure path that can leave local secondmate retirement permanently inconsistent.

Testing

Inspected the target diff and credential availability, captured direct CLI evidence for absent-key and no-rules fallback behavior, and ran the focused resolver, bootstrap, and spawn-profile suites successfully. No UI surface was involved, so CLI transcripts are the appropriate reviewer-visible evidence. A real Jev call could not be exercised without TYPESAFE_API_KEY.

  • Live validation: ⚠️ inconclusive - 2 of 4 scenarios driven live against the product
Scenario Result Live Evidence
Without a Typesafe key, dispatch resolution stays off and preserves existing routing ✅ pass live Live no-key fallback transcript
An opted-in home with no typed rules returns control to existing intake ✅ pass live Live no-rules fallback transcript
A clear real Jev answer resolves to a concrete harness, model, and effort profile ⏸️ untested no No TYPESAFE_API_KEY is available. Supply it through the test process environment or the isolated test home's .env, with a real crew-dispatch rules file and quota-axi access.
Low-confidence, captain-approval, and quota-restricted answers never auto-dispatch ⏸️ untested no No TYPESAFE_API_KEY is available. Supply it through the test process environment or the isolated test home's .env and rerun against the real Typesafe API.
Evidence: Live no-key fallback transcript

Source: Live no-key fallback transcript

exit=0; stdout empty; stderr reports typed dispatch is off because TYPESAFE_API_KEY is absent.

$ env -u TYPESAFE_API_KEY FM_HOME=<isolated-home> bin/fm-dispatch-resolve.sh
exit=0
stdout:
stderr:
dispatch-resolve: off (TYPESAFE_API_KEY absent from the environment and ~/.no-mistakes/evidence/01M2Q5D39PMHXSDCV8MSYQH9VJ/dispatch-off-home/.env)
Evidence: Live no-rules fallback transcript

Source: Live no-rules fallback transcript

exit=0; status=escalate; reason=no rules to match.

$ TYPESAFE_API_KEY=<nonempty test value> FM_HOME=<isolated-home-with-no-rules> bin/fm-dispatch-resolve.sh <brief>
exit=0
stdout:
dispatch-resolve:
  status: escalate
  reason: no rules to match
stderr:
- Outcome: ⚠️ 2 warnings across 1 run (6m4s)

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

⏭️ **Rebase** - skipped

Step was skipped.

⚠️ **Review** - 1 error
  • 🚨 bin/fm-teardown.sh:3409 - Local secondmate retirement removes the home before deleting its pending-reply records. If that later cleanup fails, for example because state/pending-replies is readable but not writable, teardown exits while preserving the registry route and metadata even though the home is already gone; a rerun then cannot pass home validation, leaving an unrecoverable half-retired route. Fixing this safely requires authorization for transactional staging: stage the matching records before home removal, restore them if removal fails, and commit their deletion only after removal succeeds.
⚠️ **Test** - 2 warnings
  • ⚠️ A real Jev request could not be demonstrated because TYPESAFE_API_KEY is absent from both the test process and worktree. Re-run this phase with the key supplied to the process or an isolated test home's .env to obtain live evidence for clear, confidence-gated, approval-gated, and quota-gated model results.
  • ⚠️ live validation verdict: inconclusive (2 of 4 scenarios were driven live against the product); untested: A clear real Jev answer resolves to a concrete harness, model, and effort profile, Low-confidence, captain-approval, and quota-restricted answers never auto-dispatch
  • Live validation: ⚠️ inconclusive - 2 of 4 scenarios driven live against the product
Scenario Result Live Evidence
Without a Typesafe key, dispatch resolution stays off and preserves existing routing ✅ pass live Live no-key fallback transcript
An opted-in home with no typed rules returns control to existing intake ✅ pass live Live no-rules fallback transcript
A clear real Jev answer resolves to a concrete harness, model, and effort profile ⏸️ untested no No TYPESAFE_API_KEY is available. Supply it through the test process environment or the isolated test home's .env, with a real crew-dispatch rules file and quota-axi access.
Low-confidence, captain-approval, and quota-restricted answers never auto-dispatch ⏸️ untested no No TYPESAFE_API_KEY is available. Supply it through the test process environment or the isolated test home's .env and rerun against the real Typesafe API.
  • Credential presence check for the process and worktree without printing secret values
  • env -u TYPESAFE_API_KEY FM_HOME=<isolated-home> bin/fm-dispatch-resolve.sh
  • TYPESAFE_API_KEY=<nonempty test value> FM_HOME=<isolated-home-with-no-rules> bin/fm-dispatch-resolve.sh <brief> --project demo
  • bash tests/fm-dispatch-resolve.test.sh
  • bash tests/fm-bootstrap.test.sh
  • bash tests/fm-spawn-dispatch-profile.test.sh
  • git status --short confirmed testing left the worktree clean
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

jokim1 and others added 13 commits September 16, 2026 04:17
* fix(bin): derive passed PR state from PR record

A completed no-mistakes run with outcome=passed does not prove the associated pull request merged or closed. A parked gate can be approved on other evidence, so the old crew-state label could report an open PR as merged and make teardown look safe when unlanded work still exists.

For passed runs, derive the crew-state detail from the run or task PR identity, accept a matching merge-poll retirement receipt as local merged evidence, and otherwise perform a bounded forge read. If the identity is absent or unreadable, report the run as passed with unknown PR state instead of inventing a merged claim.

Fixes kunchenguid#4607

* no-mistakes(review): Add bounded GitLab merge-request state reads

* no-mistakes(review): Preserve network-free inactive crew-state scans

* no-mistakes(document): Document PR record readers in shared library
kunchenguid#4627)

* fix: restore published contribution follow-up (Fixes kunchenguid#4469)

* fix(review): Fix contribution freshness and merge actor routing

* fix(review): Restore issue triage and scope contribution follow-up

* fix(test): test: assert one wake per contribution signal

* fix(document): Document contribution follow-up

* fix: restore truthful terminal delivery evidence

* fix(review): Disclose unsupported contributions and deduplicate watcher wakes

* fix(review): Preserve unmeasured unsupported contributions across Bearings

* fix(review): Deduplicate shared contribution wakes and isolate diagnostics

* fix(ci): Captain, fixed the CI failure by updating the PR-security fake GitHub interface to support the contribution observer’s API reads. Verified with shellcheck, git diff --check, the full contribution suite, and a focused merged-poll retirement reproduction. The full PR-security script was not allowed to complete locally after its expanded observer path made it substantially slower
…nguid#4658)

* fix(bin): make a remote-reply document gap self-clearing and re-attemptable

A remote mate's undelivered document raised a keyed `blocked` decision that
nothing could ever resolve, and any `data/*.md` substring in any mirrored line
was an unconditional fetch instruction. A mate announcing a report it had not
written yet therefore manufactured a permanent, factually false blocker, and
its own explanation of the false alarm manufactured more.

The reader has no permanence vocabulary: a report still being written refuses
exactly like a path that will never exist. So an undelivered document is now a
durable, re-attemptable obligation under `state/remote-replies/<id>.pending-docs`,
re-attempted on the next delta and on the channel's own quiet poll, and retired
with a matching `resolved` line naming the local copy once it arrives. The
cursor still advances and no delta stalls on one bad pointer.

Only a structured `report=data/....md` pointer now offers a document, so a path
merely mentioned in prose - including one under another home's mirror tree,
which is provably not that mate's to serve - is never fetched. Offers are
deduplicated across the whole delta, the escalation names each missing document
once and carries the reader's own reason instead of discarding it, and a
strictly increasing notice ordinal keeps a later escalation from being
swallowed as duplicate bytes. A mirrored line still lands once whichever
pointer form it was first written under.

* no-mistakes(review): Require structured pointer token boundaries

* no-mistakes(review): Unify boundary-safe pointer extraction and rewriting

* fix(bin): identify a mirrored line independently of its delivery state

Two defects in the boundary-safe pointer work.

The at-most-once check compared only the all-remote and all-local renderings
of a line, so it could not recognize a mixed one. A line offering two documents
where only the first was deliverable mirrored as local-plus-remote; once the
second arrived, a cursor-loss whole-log recapture rendered the same line
all-local, matched neither alternate, and mirrored a second time. A line's
identity is now the canonical form every boundary-valid pointer would take once
delivered, derived by the same parser that does extraction and rewriting, so it
no longer depends on which documents happened to be deliverable at the time.

The pointer map was passed to awk through the process environment. A delta may
carry up to the configured 1 MiB bound, and an expanded map of delivered
pointers can exceed the platform's exec argument limit, so awk would fail to
start; because no caller checked, the empty result would have been appended as
blank lines while the cursor advanced past dropped status content. The map now
travels in a file, and every call site checks the exit status and stops the
ingest rather than committing a delta it could not render.

Both passes now run once per stream instead of twice per line.

* no-mistakes(review): Abort ingest when document pointer extraction fails

* no-mistakes(review): Exclude structured cross-home pointers from document transfer

* fix(bin): fail open on an undeliverable remote document instead of tracking it

Narrow the remote-reply document fix to the scope the diagnosis actually
requires, as decided after measuring a simpler alternative.

A document the reader cannot deliver now fails open. The mate's line is
mirrored with its own pointer, the cursor advances, and one unkeyed note
carries the reader's reason. A note never enters the open-decision fold, so it
cannot stand open the way the original keyed block did - which removes the
never-clearing false blocker by construction rather than by resolving it.

That makes the durable self-clearing obligation unnecessary, so it goes: the
per-mate pending-documents record, its notice ordinal and resolved
announcements, and the poll-side retry. Canonical line identity goes too, and
with it a way to silently drop a genuine status line; mirroring is back to
at-most-once on exact bytes. The cross-home exclusion goes as well: under
fail-open a cross-home report= either fails harmlessly or is a nested remote
report this mate genuinely holds, which is now relayed again.

Kept: fetching only on a structured report= pointer, the boundary-correct
parser, the file-based rewrite map, and checked extraction and rewrite exit
status. The parser now scans behind a sentinel byte so a rejected candidate can
no longer give the text right after it a false leading boundary.

The reported incident is covered end to end: a report path announced in prose
before it exists raises no decision, and the report still arrives through the
ledger publisher's structured offer once written.

* no-mistakes(review): Preserve source-line identity across remote reply replays

* no-mistakes(document): Document remote reply transfer and replay semantics

* no-mistakes(lint): Fix staging truncation lint checks
* Preserve substantive Calm mid-turn text

* no-mistakes(review): Distinguish newline-preserved replies from short narration

* no-mistakes(document): Document Calm mid-turn preservation boundaries

* no-mistakes(ci): Fixed the flaky contribution watcher test by increasing its bounded checkpoint from 5 to 15 seconds, allowing diagnostics to surface under slower CI load. Verified with `bash tests/fm-contributions.test.sh` and `git diff --check`
…#4656)

* fix(bin): re-record PR poll identity after a volume device renumber (Fixes kunchenguid#4260)

A volume remount can renumber the state filesystem's st_dev while every
inode and byte stays the same; APFS does this across a reboot. A poll
registration records its sidecar and check as device:inode, so every poll
armed before the remount failed strict validation and the watcher refused
all of them as unauthenticated state checks until each was re-armed by hand.

There are two device comparisons. fm_pr_private_file_valid compares a live
file's device with the state directory's device read in the same invocation:
it refuses a file that is not on the state directory's own filesystem and
already survives a renumber, so it is unchanged. The registration's recorded
identity versus the live identity (from kunchenguid#556, reused by the kunchenguid#932 retirement
receipt) binds the registration to the exact files published in its own
transaction; its device part is what breaks.

When strict capture fails, the watcher now proves the device is the only
difference: every other artifact check passes (template bytes, both hashes,
private mode, single link, live device, metadata), both recorded identities
name one device, and each recorded inode equals its live inode. Only then,
under the task's control lock, does it rewrite the two identity lines,
repeating the whole proof and comparing the registration's file identity and
bytes just before the rename, and then capture strictly again. A swapped,
altered, re-moded, relinked, split-device, or foreign-device artifact still
fails a proof and is still refused, and a pending retirement receipt blocks
the rewrite.

Reproduction: on macOS a poll armed on an APFS disk image that was detached
and re-attached behind another image moved st_dev 16777239 -> 16777243 with
inodes, bytes, mode, and link count unchanged; the real watcher refused it on
main and reports its merge with this change. The portable regression test
rewrites a real registration's recorded device and drives the watcher.

Not changed here: the status presentation cursor keys rows by its own
device:inode identity in bin/fm-classify-lib.sh, a different helper that
needs its own fix; a retirement receipt left by a reboot between its
publication and removal still names the old device and stays refused; custom
check trust binds only a content hash and is unaffected.

* fix(review): Serialize PR poll publication writers

* fix(review): Bound PR poll publication lock scope
…llow-up to kunchenguid#4627) (kunchenguid#4661)

A budget that expires partway through an observation no longer records an
error or prints the unavailable wake; the URL keeps its prior record and is
observed first next poll. forge() flags budget exhaustion at the point it
refuses, or when a read is killed at the budget's own deadline, so a genuine
forge failure still records the error and wakes. Each distinct URL is now
observed once per poll and applied to every owning task.
…kunchenguid#4680)

* fix(bin): clear parent pending-replies on local secondmate retirement

Local secondmate teardown left resolved parent pending-reply records behind
after home removal (seen after papa-hdds / pxmx retirement). Refuse non-forced
retirement while any reply for that id is still unresolved, and delete every
matching record plus its delivery confirmation after a successful local or
remote retirement, matching the remote cleanup path.

* no-mistakes(document): Align secondmate retirement docs with pending-reply cleanup

* no-mistakes(review): Lokale Pending-replies-Sicherheitsprüfung vor Home-Entfernung

* no-mistakes(review): Pending-replies-corr_id auf 16-Hex absichern

* no-mistakes(review): Pending-replies Basename und corr_id abgleichen

* no-mistakes(document): Clarify forced retirement pending-reply cleanup

---------

Co-authored-by: ladwein <ladwein@firstmate.bost8.thelad.loc>
kunchenguid#4677)

* fix(bin): accept Orca's composite worktree id at teardown

Teardown refused every Orca-backed task because the endpoint validator
checked orca_worktree_id with the simple-atom rule meant for tmux-style
window names, which rejects any character outside [A-Za-z0-9._@%+-]. Orca
returns that id as `<orca id>::<absolute worktree path>`, so the colon and
slashes in every real value made validation fail and finished Orca tasks
could never be cleaned up.

Validate the field as the composite it is: both halves of the first `::`
split present, the path half absolute, and no embedded newline, carriage
return, or tab. The terminal field keeps the atom check, which is correct
for it, and no other backend's validation changes.

The existing Orca fixtures recorded ids like `wt-teardown`, a shape Orca
never returns, which is why the suite passed a check the real value fails.
They now carry the composite form, so the tests exercise the real value.

* no-mistakes(document): name Orca's repo id in the composite worktree id

* no-mistakes(document): list teardown endpoint safety suite in Orca regression entry points
* feat(bin): add opt-in typed dispatch resolution through typesafe.ai

Add bin/fm-dispatch-resolve.sh, which resolves one concrete crewmate or
scout profile from a written brief with typesafe.ai's System One model:
one Choice question over the rules' `when` texts, then the confidence
floor, the rule's `approval` and `floor`, each profile's `provider` and
`floor`, one quota-axi snapshot, and the spendPriority argmax all in code.
It is off unless TYPESAFE_API_KEY is in the environment or the home's
gitignored .env; off means one stderr line, exit 0, and no network call,
so firstmate dispatches exactly as before. The key reaches curl on a file
descriptor, never argv.

Extract fmx_env_get into bin/fm-env-lib.sh as the one .env accessor and
the harness-to-provider table into bin/fm-quota-axi-lib.sh so the new
tool and bin/fm-quota-choose.sh share one owner each. Bootstrap validates
the four new optional dispatch fields. Document the schema, the operator
contract, the AGENTS.md intake step, and the live and benchmark evidence.

* no-mistakes(review): Harden typed dispatch resolution and quota bounds

* no-mistakes(review): Validate dispatch floors and ranking evidence

* no-mistakes(review): Tighten dispatch response and floor evidence

* no-mistakes(review): Neutralize none matching and resolve defaults locally

* no-mistakes(review): Preserve providerless profiles outside typed resolution

* no-mistakes(review): Validate response usage and reject duplicate profiles

* no-mistakes(review): Escalate unverifiable floors and validate probabilities

* no-mistakes(review): Validate probability mass and unknown profile floors

* no-mistakes(review): Simplify resolver interface and preserve fallback routing

* no-mistakes(review): Fix constants and rank partial quota evidence

* no-mistakes(review): Add authoritative provider mapping and enforce explicit providers

* no-mistakes(review): Declare provider for documented Pi profile

* no-mistakes(review): Validate provider identifiers and support Gemini dispatch

* no-mistakes(review): Strictly anchor provider identifiers

* no-mistakes(review): Validate selectors and preserve fallback candidate evidence

* no-mistakes(review): Gate typed validation and harden resolver evidence

* no-mistakes(review): Preserve opt-in routing and harden candidate evidence

* no-mistakes(review): Prioritize known exhaustion over quota uncertainty

* no-mistakes(review): Isolate API secrets and preserve no-key diagnostics

* no-mistakes(review): Fallback safely when dispatch rules are absent

* no-mistakes(review): Prioritize quota vetoes and isolate bootstrap secrets

* no-mistakes(document): Document typed dispatch safety and fallback behavior
…n decisions aren't lost (kunchenguid#3753)

* test: reproduce buried status declarations in shared readers

* fix: share status event reads and preserve open blockers

* fix: retain terminal scout and ship status declarations

* no-mistakes(review): Fix status chronology, legacy completions, and reader performance

* no-mistakes(review): Share terminal decision reconciliation across fleet snapshots

* no-mistakes(review): Unify terminal supersession across cached folds and consumers

* no-mistakes(review): Filter per-key status history while preserving terminal chronology

* no-mistakes(test): Preserve parent lock ownership in Bash 3.2 subshells

* no-mistakes(review): Anchor legacy status tokens so prose cannot hide pauses

* no-mistakes(document): Document latest-event status read and kind-scoped fold cursor

* no-mistakes(lint): Quote literal done in test for-lists for SC1010

* ci: expect 19 snapshot/fleet-view tests

This branch adds a fleet-snapshot regression, so the stock macOS Bash
lane's hardcoded guard of 18 'ok - ' lines fails on the new count.
Bump the guard and its message to 19.

* no-mistakes(review): Restore multiline child outcome reporting

* no-mistakes(review): Select ledger terminal events through bounded shared reader

* no-mistakes(review): Report newest open decision instead of preferring blocked

* no-mistakes(review): Require colon before ship/scout terminal supersession in fold

* no-mistakes(review): Gate socket-down override on latest event; drop lock matrix

* no-mistakes(review): Fold only colon-bearing or keyed lines as decision transitions

* no-mistakes(review): Pre-select candidate lines before per-key closing-verb fold

* no-mistakes(test): Update fleet-view expectations to newest-open-decision rule

* no-mistakes(document): Align status-read docs with fold-resolved crew state

* no-mistakes(document): Correct status-reader contracts in classify-lib and crew-state headers

* no-mistakes(ci): Greptile P1 (bin/fm-crew-state.sh:729, "Stale socket blocker survives") was a real defect introduced by commit b7c2183 on this branch, and is fixed. Root cause: the daemon-socket-down override took its verb check from `last_status_line "$LOG"` but its evidence and emitted detail from `$LOG_LINE` (status_current_line = the fold's newest still-open decision). Those are different lines whenever a later recognized `blocked:` event is one the decision fold declines. Reproduced by sourcing bin/fm-classify-lib.sh on `blocked: no-mistakes daemon socket is missing` followed by `blocked [key=pending-reply-t3]: still waiting on the answer` (reserved-namespace key whose note does not speak that vocabulary, so _fm_decision_key_transition_allowed rejects it): open set still holds the socket blocker, last_status_line returns the newer line, its verb is blocked, so the gate passed and the stale daemon-down evidence overrode a healthy attributed run. Fix (bin/fm-crew-state.sh): capture LOG_LATEST=$(last_status_line "$LOG") once and read verb, socket-down evidence, and the emitted note all off that same line, so the override fires only while the socket-down declaration is itself the log's latest recognized event — preserving the narrow override the prior round's user instruction asked for. Comment updated to state that contract. No new machinery; the two-line conflation was removed rather than papered over. Regression: extended tests/fm-crew-state.test.sh:test_socket_refusal_override_expires_when_the_crew_moves_on with the reproduced sequence, asserting the run-step reading (state: working, source: run-step) and absence of the override detail. It fails before the fix ("not ok - a later unfolded blocked event also hands the reading back to the run (missing: 'state: working')") and passes after. Verified locally: tests/fm-crew-state.test.sh, tests/fm-fleet-snapshot-view.test.sh, tests/fm-classify-decision-key.test.sh, tests/fm-watch-triage.test.sh, tests/fm-captain-hold-lifecycle.test.sh all pass; bin/fm-lint.sh (shellcheck 0.11.0 + actionlint) exits 0. Changes left uncommitted in the worktree

* test: fold terminal-cleanup snapshot coverage into the completed-scout case

Keep the ship/scout/secondmate supersession assertions without adding a
nineteenth top-level fleet-view test, so CI can stay at the upstream suite count.

* no-mistakes(document): Clarify socket-down override expiry in architecture doc

* ci: retrigger flaky contribution check
…nchenguid#4689)

* fix(spawn): launch codex crewmates with codex's hook layer disabled

A freshly launched Codex worker never reached its instructions. Codex
stopped it on an interactive "Hooks need review" modal whose selection
sits on "Review hooks", which is neither trusting nor declining.
Firstmate's key plane carries only Enter, Escape and Ctrl-C with no arrow
navigation, so the selection cannot be moved, and pre-accepting the
prompt by writing Codex's own trust store would record an operator
consent that was never given.

The hooks are the machine's own ~/.codex/hooks.json plus any project's
.codex/hooks.json. A crewmate needs neither: its turn-end signal is the
-c notify= program on the same launch, and Firstmate's project hooks are
primary-session infrastructure that stands down in a child worktree.

Crewmate and scout launches now pass --disable hooks. That is the
opposite of --dangerously-bypass-hook-trust, which RUNS the untrusted
hooks; disabling the feature runs none of them and leaves the operator's
~/.codex untouched. An unknown feature name is a hard Codex error, so a
release that drops the flag fails the launch loudly instead of silently
restoring the modal. A secondmate is a primary in its own home and keeps
the project hooks its turn-end guard and session-start digest ride on.

Verified on codex-cli 0.151.0: the modal is gone and the turn-end
notification still lands.

This unblocks the second review that every finished pull request is supposed to get.

Fixes kunchenguid#4673

* no-mistakes(review): Fix contradictory hook count in Codex verification record
Integrate upstream fa93097 while
retaining the fork's Vault, lifecycle, Orchestra, lock, and repair behavior.

Keep lifecycle filtering in contribution-call presentation with explicit
suppression counts and per-home identity, without changing contribution
storage, polling, or coverage totals. Declare the new Bearings surface and
refresh fork-only test timing hints from green CI measurements.
@rega10 rega10 changed the title feat(bin): add opt-in typed dispatch resolution Merge upstream main for opt-in Jev dispatch Sep 17, 2026
@rega10
rega10 merged commit 11764c0 into main Sep 17, 2026
16 checks passed
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.

8 participants