Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions docs/hygiene-history/ticks/2026/05/15/0213Z.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Tick 0213Z — PR #3349 opened + auto-merge armed; TSC strict-mode fix landed on save-ai-memory canonical TS impl

## Headline

- PR [#3349](https://github.com/Lucent-Financial-Group/Zeta/pull/3349) OPENED + auto-merge armed. Resolves 6 `tsc` strict-mode errors in `tools/save-ai-memory/process-extract.ts` (the canonical TS impl that landed in [#3337](https://github.com/Lucent-Financial-Group/Zeta/pull/3337)). Currently `BLOCKED gate / 0 failed required / autoMerge armed / wait-ci`.
- Fix shape: `nextArg(name)` helper guards `string | undefined` from `argv[++i]`; `name.charAt(0)` replaces `name[0]` for `noUncheckedIndexedAccess`-clean access. One file, 17/8 line delta.
- Real footgun caught by strict mode: pre-fix, `bun process-extract.ts --ai-name` (missing value) would silently swallow the next flag as the value. Post-fix exits 1 with `Missing value for --ai-name`.

## What I found mid-tick (substrate-honest disclosure)

- Stale `.git/rebase-merge/` directory pointing at `lior/decompose-b0139-4` (May 14 20:36 mtime, ~1.5hrs old) sitting in the primary worktree's `.git/`. My HEAD was correctly on `fix/save-ai-memory-tsc-errors-otto-cli-2026-05-15`; the orphaned rebase state is orthogonal to my branch ref. Did NOT touch it per [`.claude/rules/claim-acquire-before-worktree-work.md`](../../../../../../.claude/rules/claim-acquire-before-worktree-work.md) worktree force-remove guard (analogous principle for peer-agent rebase state).
- Inline branch guard (`test "$(git branch --show-current)" = "<expected>" && git commit`) used per [`.claude/rules/zeta-expected-branch.md`](../../../../../../.claude/rules/zeta-expected-branch.md) field-test caveat — the env-var hook is defense-in-depth, not primary.
- Explicit `--head` passed to `gh pr create` per the same rule's companion defense.

## Δ since 0051Z (last shard)

| What | Before | After |
|---|---|---|
| Main HEAD | `e692e90` (#3330) | `343aef4` (#3338) — 5 PRs merged in the gap |
| Otto-CLI open PRs | 1 (#3332) | 1 (#3349) |
| `tsc --noEmit` clean? | NO (6 errors in save-ai-memory) | YES |
| save-ai-memory CLI arg-handling | silent on missing value | `Missing value for <flag>` + exit 1 |

## Cron sentinel

`a2c54a1c` armed at session start (CronList was empty — fresh-session catch-43-defence fired).

## Next

Cron-driven. Next tick verifies #3349 merge state. If still BLOCKED, investigate threads. If MERGED, scan ready-to-grind backlog rows (3 work-assignment envelopes from 23:58Z still pending: B-0441, B-0170, B-0503; some may have expired at 01:58Z — check before claiming).
48 changes: 39 additions & 9 deletions tools/save-ai-memory/process-extract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,15 @@ import { execFileSync } from "node:child_process";

type Platform = "grok" | "chatgpt" | "claudeai" | "gemini" | "deepseek" | "unknown";

const ALLOWED_PLATFORMS: ReadonlySet<string> = new Set([
"grok",
"chatgpt",
"claudeai",
"gemini",
"deepseek",
"unknown",
]);

interface Args {
aiName: string;
platform: Platform;
Expand All @@ -83,26 +92,47 @@ function parseArgs(argv: string[]): Args {
commit: false,
dryRun: false,
};
for (let i = 0; i < argv.length; i++) {
let i = 0;
function nextArg(name: string): string {
const v = argv[++i];
if (v === undefined) {
console.error(`Missing value for ${name}`);
process.exit(1);
}
if (v.startsWith("--")) {
console.error(`Missing value for ${name} (next token "${v}" looks like a flag)`);
process.exit(1);
}
return v;
Comment thread
AceHack marked this conversation as resolved.
}
for (; i < argv.length; i++) {
const a = argv[i];
switch (a) {
case "--ai-name":
args.aiName = argv[++i];
args.aiName = nextArg("--ai-name");
break;
case "--platform":
args.platform = argv[++i] as Platform;
case "--platform": {
const raw = nextArg("--platform");
if (!ALLOWED_PLATFORMS.has(raw)) {
console.error(
`Invalid --platform "${raw}". Allowed: ${[...ALLOWED_PLATFORMS].join(", ")}`,
);
process.exit(1);
}
args.platform = raw as Platform;
break;
}
case "--topic":
args.topic = argv[++i];
args.topic = nextArg("--topic");
break;
case "--conversation-id":
args.conversationId = argv[++i];
args.conversationId = nextArg("--conversation-id");
break;
case "--input":
args.input = argv[++i];
args.input = nextArg("--input");
break;
case "--output":
args.output = argv[++i];
args.output = nextArg("--output");
break;
case "--scrub-emails":
args.scrubEmails = true;
Expand Down Expand Up @@ -245,7 +275,7 @@ function generateOutputPath(args: Args, isoDate: string): string {

function capitalizeName(name: string): string {
if (name.length === 0) return name;
return name[0].toUpperCase() + name.slice(1);
return name.charAt(0).toUpperCase() + name.slice(1);
}

function buildArchive(
Expand Down
Loading