Skip to content

fix: a typo'd fdeops command errors instead of installing; LOG shows each contact once - #33

Open
devin-ai-integration[bot] wants to merge 3 commits into
Mainfrom
devin/1786321445-launch-polish
Open

fix: a typo'd fdeops command errors instead of installing; LOG shows each contact once#33
devin-ai-integration[bot] wants to merge 3 commits into
Mainfrom
devin/1786321445-launch-polish

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Summary

First-impression defects found by a fresh-user pass over merged trunk (f4214b8), tested against the published package rather than a checkout.

1. fdeops <anything-unknown> silently performed a full install. bin/install.js dispatched init/adapters/FDE_SUBCOMMANDS and let everything else fall through to cmdInstall(), exit 0. So npx fdeops Demo (or dmeo, dashbord) rewrote ~/.claude/skills, ~/.claude/hooks/fdeops-* and ~/.claude/fdeops/fde.js, never ran the demo, and reported success. Verbs now resolve case-insensitively, and an unrecognized one exits 1 with a nearest-match suggestion; bare npx fdeops still installs.

- fdeops Demo   → exit 0, install banner, ~/.claude rewritten
+ fdeops Demo   → runs the demo
+ fdeops dmeo   → exit 1  "unknown command 'dmeo' - did you mean 'demo'?"
+ fdeops        → installs, unchanged

2. Every fde log contact entry rendered twice in the fieldbook LOG panel. fde log contact deliberately records into both stakeholders.md "## Signal history" and .signal-ledger (the ledger survives an agent rewriting the markdown), and the timeline reads both. Two contacts showed as four adjacent identical rows — it reads as "this tool double-writes my data", which is the opposite of the pitch. Collapsed at read time, so both storage locations stay:

entries.sort(...)
+ // same kind|date|signal|text from two sources is one event
+ return dedupe(entries).slice(0, 15)

The signal is part of the key on purpose: an amber note escalated to red the same day is two real events, and they must not collapse into one. Which then required (6).

3. doctor said nothing about unbalanced <private> markers. Not a sealed-block leak — non-greedy pairing is working as designed — but the user's intent silently differs from the result: a stray </private> leaves everything after it public, and a forgotten closer seals every note appended later. doctor now reports counts per file, never the sealed text:

2. risks.md has 1 unclosed <private> - everything after it is sealed, including notes added later
3. context.md has 1 unmatched </private> - text after it is PUBLIC; pair or delete the marker

4. A copy failure named the wrong path. ~/.claude/skills/fde - permission denied at <package>/skills/fde/references/ai.md pointed the user at a file inside the package they can't fix; the unwritable path is the destination, so destPathFor() re-roots the reported path under dest.

5. fdeops --help / --version installed. Fixing (1) by filtering dash-prefixed args out of positional left flag-only invocations with no verb at all, so they fell through to cmdInstall() — asking the tool a question rewrote ~/.claude. Help and version are now answered before dispatch and touch nothing.

6. A flag before the verb ate the verb's argument, and is now rejected outright. The first pass set process.argv[2] = arg in place, so fdeops --force redact ledger left --force sitting where the CLI expects the search term:

- process.argv[2] = arg                    // → fde redact "--force" "ledger"
+ const rest = argv.slice(argv.indexOf(raw) + 1)
+ process.argv = [argv0, argv1, verb, ...rest]

A flag typed there belongs to fdeops, not to the command, and forwarding it would silently change what the command operates on. So rather than dropping it quietly — fdeops --all status exiting 0 having ignored --all — anything outside --force/--help/--version before the verb exits 1 and says where the option belongs.

7. An escalation looked like a double write. With (2) in place, amber then red on the same note correctly renders two rows — but the row markup carried date/kind/text only, so the two rows were pixel-identical. Rows now render the signal (● red), which is also the first place the timeline shows trust movement at all.

Also dropped the "60-second walkthrough" wording from fde demo help — it takes ~0.4s, and this repo's whole thesis is claims that check out.

Five regression tests, each verified to fail with the fix reverted. npm run check = 53 gates + 91/91 tests. Full runtime evidence (dispatch matrix, LOG counts parsed from row markup, installer/privacy/demo regression, dashboard --open in real Chrome) is in the verification comment below.

Link to Devin session: https://app.devin.ai/sessions/f135381c4682413bae73dff38eb6d1a3
Requested by: @suboss87

…LOG panel

- `fdeops <typo>` (including `Demo`/`DEMO`) exited 0, printed the install
  banner and rewrote ~/.claude instead of running anything. Verbs now match
  case-insensitively and anything unrecognized exits 1 with a suggestion;
  bare `npx fdeops` still installs.
- The fieldbook LOG rendered every `fde log contact` entry twice, because the
  timeline reads both stakeholders.md and .signal-ledger (the CLI writes both
  on purpose). Identical rows are collapsed at read time.
- doctor now flags unbalanced <private> markers: a stray closer leaves the
  following text public, a forgotten opener seals later notes. Counts only.
- A copy failure named the source path inside the package; it now names the
  destination the user can actually fix.
@suboss87 suboss87 self-assigned this Aug 10, 2026
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

…ag no longer eats the verb

- `fdeops --help`/`-h` printed the install banner and rewrote ~/.claude at
  exit 0, because the positional filter dropped every dash-prefixed argument.
  Flags now answer: --help routes to the CLI help, --version prints the
  version, and only a genuinely empty (or install-flag-only) argv installs.
- `fdeops --force redact ledger` searched for "--force ledger": the verb was
  no longer argv[2] after the rewrite. The hand-off now passes the verb first
  plus only what followed it - a flag typed before the verb belongs to fdeops.
- FDE_SUBCOMMANDS was missing `preserve`, which fde.js implements.
- The LOG de-dup key now includes the signal, so the same note logged amber
  then red on one day stays two rows: that is an escalation, not a duplicate.
…re the verb

Two cosmetic gaps left by the previous commit:

- A same-day amber then red note is two LOG rows by design, but the row
  markup carried date/kind/text only, so an escalation looked like a double
  write. Rows now render the signal (colored dot + label).
- A flag typed before the verb is fdeops' own and is not forwarded, which
  meant `fdeops --all status` silently ignored --all at exit 0. Anything
  outside --force/--help/--version there now exits 1 and says where the
  option belongs.
@devin-ai-integration

devin-ai-integration Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor Author

Runtime verification — launch polish

Tested the published package built from this branch (npm pack → global install → run from a directory with no checkout), disposable HOME per case and sandboxed engagement roots throughout. Baseline npm run check exit 0, 91/91; installed bin/*.js byte-identical to the branch; real ~/fde-engagements never created.

Verification below is against 3905844; 1037d1a then closed the two cosmetic findings it raised (signal shown on LOG rows; an unknown option before the verb now exits 1 instead of being dropped).

Dispatch: asking a question no longer writes to ~/.claude, and a leading flag no longer corrupts the argument
case result
--help / -h / --version / -v (+ -H, --HELP, each with a trailing --force) exit 0, help or 3.9.20, $HOME clean
bare fdeops, --force, install, install --force, --force install exit 0, skills + 3 hooks installed
9 typo'd verbs incl. presrve, Dmeo exit 1, correct did you mean, $HOME clean
Demo / DEMO / DeMo / Scan / HELP / PRESERVE run the command, install nothing
preserve dispatches (was "unknown command")
--force redact X vs redact X same term (previously searched "--force X")

19 valid verbs were compared differentially against fde — identical exit codes, $HOME/.claude never created.

Flags after the verb were verified with flags whose effect is observable, not just exit codes: redact --apply <term> parsed the term and deleted only the matching line; log --signal red/amber wrote the token to both storage locations while --signal purple still exits 1 (so the value forwards); log --undo restored byte-identical state; log --force overrode the secret refusal; debrief --smart FILE --apply committed decision + risk, reversed order identical; dashboard --all/--out wrote the expected files; demo --clean removed .demo with a decoy real client byte-identical.

Dispatch matrix

Flag forwarding with observable effects

LOG: each contact once, escalations still two rows

Counted by parsing only fb-row fb-log blocks — a whole-file grep double-counts, since row text also appears in the People panel.

case on disk rendered
one log contact stakeholders.md and .signal-ledger 1 row (no data loss)
4 byte-identical rows 4 1
amber → red, same day/text 4 2
distinct same-day text · same date+text different kind both render
15 unique + 3 exact dupes 18 15, UNIQUE-OLDEST-15 retained (de-dup precedes the slice)
fde prep agrees with the dashboard; shows [red] (latest)

Amber-to-red escalation renders as two rows

Exact duplicates still collapse to one row

Top-15 boundary: 18 raw rows render 15

Installer, privacy, doctor, demo (regression)

install.js changed, so the install matrix was re-run: permission failure → exit 1, permission denied at <path under $HOME>, 0 package-source paths, 0 stack frames, install continued (3 hooks), and chmod u+w on exactly the reported path makes the re-run exit 0 and restore the file. Symlink refusal ± --force: refused, target byte-identical, 0 stray managed markers.

Privacy through the rewritten dispatch: needle 0 across 13 model-facing commands and 0 in both rendered HTMLs, marker rendered, needle preserved on disk. doctor marker counts on a non-fresh engagement: 9 shapes all exact (nested/attribute/balanced silent; 3-openers-1-closer → 2 unclosed; 2 strays → 2 unmatched; HTML-comment marker → 1 unclosed), 0 sealed content printed. demo: 10 steps, needle 0 in transcript and HTML with the on-disk control inside <private>; 60-second appears 0 times in the installed package. dashboard --open handed xdg-open the exact plain path (0 %2F) and Chrome rendered the Fieldbook.

Note for future readers: the doctor marker check sits after the day-1 if (fresh) return issues early-return, so it cannot fire on a freshly initialized engagement — matching the "don't nag on day 1" rule.

Not tested: npx skills add suboss87/fdeops (needs network egress from the test sandbox).

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 2 additional findings.

Open in Devin Review

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.

1 participant