Task: Full-repository improvement audit at 24947bc — verified P1/P2/P3 remediation checklist
Maintainers usually reply within 1 day
@Kuldeep2822k is already working on this.
Since Oct 31, 2026.
Assessment
This issue has not been assessed yet.
Description
Description
A full-repository, read-only audit across correctness, security, performance, tests, architecture, dependencies, DX, docs, and direction. Every finding below was re-opened and confirmed in source at 24947bc; line references are against that commit. Baseline at audit time: npm run typecheck exit 0, npm run lint exit 0, npm audit reports 0 vulnerabilities.
The checklist is ordered by leverage (impact ÷ effort, discounted by confidence and fix risk). Each item is independently shippable. Done means the fix plus a regression test that fails when the deciding predicate is reverted, with the verification loop green:
npm run typecheck
npm run lint
npm test
Behavior changes also update the affected ADR or invariant (docs/adr/, planning/invariants.md, agent.md).
Scope of this issue: 12 P1, 12 P2, and 18 P3 findings, plus four direction options. Security-sensitive details are included at the maintainer's explicit request after the public-visibility warning; no secret values appear anywhere in this report.
Motivation
The repository is mature and heavily tested, but the audit found a small number of data-corruption and lost-update paths in the write-critical core (SM-2 scheduling, adoption, undo, session memory), one documented network-boundary bypass, one release-workflow injection class, and a set of smaller contract/test/perf gaps. Fixing the P1 set protects user notes and the published artifact; the P2/P3 set removes recurring classes of drift rather than individual symptoms.
Acceptance criteria
Definition of done (applies to every checked item)
- The fix is implemented in the files named by the item; no out-of-scope behavior changes.
- A regression test exists that fails when the deciding predicate is removed or reverted.
-
npm run typecheck,npm run lint, andnpm testpass. - Exit-code and
--jsoncontracts are unchanged unless the item explicitly says otherwise. - If the item changes documented behavior, the relevant ADR/invariant/README text moves with it.
P1 — data safety, contract, and boundary fixes
-
P1-01 — Cap SM-2 intervals so
due_atcannot overflow the JavaScript Date range.- Evidence:
src/engine/sm2.ts:171multipliesinterval_days * ease_factor;:190only rejects a non-finite result, not a date-range overflow;:264advances withdue.setDate(...);src/application/record-review.ts:90-112formats the result intodue_at. - Reproduced against
dist: review 15 (quality 5) writesinterval_days: 30216170anddue_at: 84755-11-24; review 16 writes120864680andNaN-NaN-NaN, with exit 0 and no error. - Impact:
palee reviewsilently persists an invalid date;valid-review-datesthen reports a manual-only error, and the invalid day disables early-review detection permanently. - Fix: after the finite check, clamp to
MAX_INTERVAL_DAYS = 36500(100 years, the common SRS ceiling); guardcomputeDueDateagainst a non-finitedue.getTime()as defense in depth; amend ADR-0001 and INV-17 to record the cap. The existing1e308non-finite throw test must keep passing. - Tests: 15/16/17 consecutive quality-5 reviews produce a valid future
YYYY-MM-DDwithin the cap;computeDueDaterefuses an invalid result; existing SM-2 tests unchanged. - Effort/Risk/Confidence: S / LOW / HIGH.
- Evidence:
-
P1-02 — Re-check a batch-adoption target's
palee_idin the preflight re-read.- Evidence: the scan stages an unadopted note at
src/cli/adopt.ts:599-612; phase 1 re-reads fresh bytes and parses frontmatter at:1374-1378but ignoresfrontmatter.palee_id; the write at:1440-1456mints a fresh ID and uses the fresh fingerprint, so OCC passes. - Impact: two overlapping
adopt --allruns (or a pause at the confirmation prompt) can make the loser overwrite the winner'spalee_idand reset its review state; dependency edges naming the first ID dangle. - Fix: after the fresh parse, if
freshFrontmatter.palee_idis a valid non-empty string (or differs from the plannednote.topicId), skip the note with an explicit conflict/skip reason; never write a replacement identity. Preserve the existing single-run behavior. - Tests: simulate the scan → preflight → write sequence with the note becoming adopted between scan and preflight; assert no second ID is written and the reason names the conflict.
- Effort/Risk/Confidence: S / LOW / HIGH.
- Evidence: the scan stages an unadopted note at
-
P1-03 — Pass the written fingerprint through undo rollback.
- Evidence:
RollbackRecordinsrc/cli/adopt-undo.ts:134-138carries no fingerprint;rollbackBatchat:383-394calls three-argumentatomicWrite, disabling OCC; adoption's sibling rollback was fixed for exactly this (#334) atsrc/cli/adopt.ts:1457-1462. - Impact: after a mid-batch undo failure, rollback blindly rewrites originals and destroys any edit made since the failed pass, while reporting restored.
- Fix: journal
computeFingerprint(item.updatedContent)aswrittenFingerprint; callatomicWrite(vault, path, originalContent, writtenFingerprint, { expectExists: true }); report a per-note conflict instead of clobbering. - Tests: edit a journaled note after the failed pass, run rollback, assert the edit survives and the conflict is reported.
- Effort/Risk/Confidence: S / LOW / HIGH.
- Evidence:
-
P1-04 — Apply the schema gate to
hot.md's newest-session selection.- Evidence:
regenerateIndexskips sessions whosepalee_schema !== SUPPORTED_SCHEMA_VERSIONatsrc/storage/memory.ts:625-636;rebuildHotAndIndexselects the newest session at:749-765with no schema check. ADR-0019:41-43 states both derived views share one eligibility predicate. - Impact:
last_sessionand the hot-memory body can name a schema-2/unlabeled session thatindex.mdexcludes; the derived views disagree and validation sees a phantom reference. - Fix: add the same
frontmatter.palee_schema === SUPPORTED_SCHEMA_VERSIONpredicate to the hot selection; keep draft/zero-byte behavior unchanged. - Tests: a newer schema-2 session plus an older schema-1 session; assert
index.mdandhot.mdboth select the schema-1 session. - Effort/Risk/Confidence: S / LOW / HIGH.
- Evidence:
-
P1-05 — Normalize a trailing root-label dot before the
.internalrefusal.- Evidence:
src/ai/provider.ts:337-352testshost.endsWith('.internal');:368-383passesURL.hostnamestraight in.new URL('https://metadata.google.internal./').hostnamekeeps the trailing dot, so the suffix test is false. ADR-0027:40 promises the.internalsuffix is refused. - Impact: the named metadata-host refusal is bypassed; an HTTPS probe of
metadata.google.internal.is permitted, violating the documented "named, not just numbered" boundary. - Fix: strip one trailing root-label dot from
URL.hostnamebefore all shape/suffix checks; addmetadata.google.internal.and mixed-case.INTERNAL.cases; confirm IPv6 and ordinary hostnames are unchanged. - Tests: the normalized endpoint is refused with the reserved-address config error;
https://api.internal-host.exampleremains allowed. - Effort/Risk/Confidence: S / LOW / HIGH.
- Evidence:
-
P1-06 — Stop interpolating manifest-derived values into release shell steps.
- Evidence:
.github/workflows/release.yml:57-68writesfilename/versionfrompackage.jsonto step outputs;:161usesVERSION=${{ needs.verify-and-pack.outputs.version }}and:171runsnpm publish ${{ needs.verify-and-pack.outputs.package-filename }}in the step holdingNPM_TOKENandid-token: write;.github/workflows/ci.yml:181,186repeats the pattern;scripts/verify-tarball.js:4buildstar -tzf ${filename}from the same manifest. - Impact: a version or filename containing shell metacharacters is parsed by the shell before npm starts, executing on the release runner with registry and OIDC credentials. Triggering requires write/tag/release access; this is a supply-chain hardening issue, not an unauthenticated attack.
- Fix: validate
name/versionagainst the npm package-name and semver rules before use; pass values throughenv:and quote them inrun:; useexecFileSyncwith an argv array inverify-tarball.js; keep the existing tarball assertions. - Tests: add a script-level validation test or a CI lint check that rejects a non-semver version; confirm the release workflow still packs, verifies, and publishes.
- Effort/Risk/Confidence: S / LOW / HIGH.
- Evidence:
-
P1-07 — Fold lock keys on case-insensitive platforms.
- Evidence:
src/storage/lock.ts:173-192hashespath.relative(realpath(vault), realpath(target))with case preserved; Node'srealpathSyncpreserves the caller's spelling on Windows (verified:D:/CLI-BUILD→D:\CLI-BUILD), whilesrc/storage/containment.ts:19-24deliberately compares case-insensitively. - Impact: two processes spelling the same note
Notes/foo.mdandnotes/foo.mdtake different lock directories, defeating mutual exclusion; creation and lock-only unlink paths can race. - Fix: fold the vault-relative lock key with
foldIdentity(lowercase + NFC) onwin32anddarwinbefore hashing; keep Linux case-sensitive. Existing lock directories are ephemeral. - Tests: on win32, acquire a lock with a case-varied spelling and assert the second spelling conflicts; on Linux, assert distinct-case paths remain distinct.
- Effort/Risk/Confidence: S / LOW-MED / HIGH.
- Evidence:
-
P1-08 — State non-existence on roadmap first-creation writes.
- Evidence:
src/cli/roadmap.ts:908-931inspects with a singlelstatand builds synthetic content forisNew;:962callsatomicWrite(vault, path, content, fingerprint)with a null fingerprint and noexpectExists, so no guard runs.AtomicWriteOptionsatsrc/storage/atomic-write.ts:200-223exists for this exact case. - Impact: a file created between the
lstatand the rename is silently overwritten — the #327 lost-update class in a.palee-writer path. - Fix: pass
{ expectExists: false }whenisNew; treat the resulting conflict as a retryable per-topic failure. - Tests: create the target after inspection and before the write; assert the original bytes survive and the conflict is reported.
- Effort/Risk/Confidence: S / LOW / HIGH.
- Evidence:
-
P1-09 — Stop matching slash-containing non-wildcard patterns at any depth.
- Evidence:
src/storage/pattern-matcher.ts:337-355appliesendsWith('/'+pattern)andincludes('/'+pattern+'/')to non-wildcard patterns even when the pattern contains/;docs/02-1-topic-management-commands.md:133says a/pattern is anchored at the vault root and must name the whole path. Directory-prefix matching (notes/caféselecting its subtree) is deliberate and pinned bytest/storage-pattern-matcher.test.ts:129-137. - Impact:
a/x.mdmatchesb/a/x.md, so--include/--excludeselect notes outside the named path; the filter reports work it was not asked to do. - Fix: for patterns containing
/, keep exact match andstartsWith(pattern + '/')(directory-prefix semantics), and drop only theendsWith/includesarms. Non-slash patterns keep basename matching. Update the dialect comment if the directory-prefix rule needs spelling out. - Tests:
matchesPattern('b/a/x.md', 'a/x.md') === false;matchesPattern('notes/café/01.md', 'notes/café') === true; existing pattern suite passes. - Effort/Risk/Confidence: S / LOW / HIGH.
- Evidence:
-
P1-10 — Apply the note read cap to adoption, undo, and roadmap.
- Evidence:
src/storage/source-cap.ts:32defines the 512 KiB cap;src/storage/loader.ts:343declines oversized notes;src/cli/adopt.ts:574,src/cli/adopt-undo.ts:762, andsrc/cli/roadmap.ts:326callreadFileSyncwith no stat guard. - Impact: a >512 KiB note is adopted and reported as a topic, but every read command skips it forever; validation shows only a read-failure. A pathological file can also exhaust memory during a batch.
- Fix: stat before read in all three write paths; refuse with
oversizedNoteDiagnostic, exit 2 or 3 per the existing command contract; no write. - Tests: a 513 KiB note is refused with the size diagnostic and no frontmatter is written; a 511 KiB note still adopts.
- Effort/Risk/Confidence: S / LOW / HIGH.
- Evidence:
-
P1-11 — Make the timezone matrix actually vary the timezone.
- Evidence:
test/timezone-matrix.test.ts:1-77never setsprocess.env.TZor spawns under a foreign zone;test/application-record-review.test.ts:13-14assertsupdates.due_atequalsformatLocalDateOnly(dueDate), the exact function under test. - Impact: under UTC CI, a
getUTC*/toISOStringregression in local-calendar due-date math passes green; the one suite named for timezones provides no cross-zone evidence. - Fix: run the date cases (or a spawned CLI case) with
TZ=America/Los_AngelesandTZ=Asia/Kolkata, asserting literalYYYY-MM-DDvalues; replace the tautological assertion with a literal date; add platform guards only where the child TZ mechanism is unavailable. - Tests: the new cross-zone cases fail if
computeDueDateis changed to UTC arithmetic; the existing UTC cases still pass. - Effort/Risk/Confidence: S / LOW / HIGH.
- Evidence:
-
P1-12 — Correct the two README rows that contradict shipped behavior.
- Evidence:
README.md:153sayssession start"starts AI tutor if provider is configured";src/cli/session.ts:504-510only reportsai_provider_configuredand never calls the provider.README.md:187saysvalidate --fixrepairs only SM-2;src/cli/validate.ts:72-80dispatchesrebuild_derived_views,recompute_topic_mastery, andreset_review_fields.test/docs-command-matrix.test.tsguards onlydocs/02-0and06-2, never the README. - Impact: users are told a Phase-2 feature runs and that
--fixonly touches SM-2, when it can rewrite derived views and mastery. - Fix: correct both rows; extend the docs matrix test to cover the README commands/options or add a targeted README test.
- Tests: the corrected claims are asserted by a test that fails on the old wording/behavior mismatch.
- Effort/Risk/Confidence: S / LOW / HIGH.
- Evidence:
P2 — correctness, security hardening, performance, and test gaps
-
P2-01 — Settle confirmation prompts on EOF.
- Evidence:
src/cli/adopt.ts:69-82,src/cli/adopt-undo.ts:152-165,src/cli/roadmap.ts:1051-1058, andsrc/cli/config.ts:296-315createreadlinequestion callbacks with noclosehandler;src/cli/session.ts:297-325has the correct pattern. - Impact: Ctrl+D at a confirmation prompt leaves the promise pending; the process exits 0 having written nothing, so aborts and successes are indistinguishable.
- Fix: resolve
false(ornull) on'close'/EOF in all four helpers, modeled onsession.ts. - Effort/Risk/Confidence: S / LOW / MED.
- Evidence:
-
P2-02 — Do not reuse a completed session ID on
session start.- Evidence:
src/cli/session.ts:488-492reusesactiveSession.session_idon topic match alone;:614-647treats that ID as already recorded;src/storage/memory.ts:510-516intentionally returns on a lock conflict, so a completed marker can survive;hasCompletedSessionexists at:1155-1165. - Impact: a stale marker makes the next
session endprintalready recordedand discard the new study time/body. - Fix: reuse the marker's ID only when
!hasCompletedSession(vault, id); otherwise rotate or clear the stale marker at start. Preserve the intentional repeated-startbehavior for an in-progress session. - Effort/Risk/Confidence: M / MED / MED.
- Evidence:
-
P2-03 — Refuse a symlinked per-target lock directory during recovery.
- Evidence:
src/storage/lock.ts:173-205containment-checks only.palee/locks;:446lists the per-target<hash>.lockdirwithreaddirSync, which follows a symlink;:516-551unlinks/renames entries inside it. - Impact: a pre-planted lockdir symlink makes stale recovery delete or rename files in the link target outside the vault before
rmdirfails. - Fix:
lstat/canonicalize the lock directory itself and refuse a symlink or non-directory before listing or sweeping; keep the existing bounded-recovery behavior. - Effort/Risk/Confidence: S / LOW / MED.
- Evidence:
-
P2-04 — Strip
PALEE_API_KEYfrom the npm child environment.- Evidence:
src/cli/update-check.ts:71-87spreadsoptionsintospawnSyncwith noenv, inheritingprocess.env;:553-565uses the same path fornpm install -g;src/cli/update.ts:59invokes it. - Impact: npm and any lifecycle script can read the provider credential. Latent today because the dependency tree has no install scripts, but one dependency change away.
- Fix: pass an explicit env to
spawnNpmwithPALEE_API_KEYremoved, preservingPATH,HOME, proxy, and npm configuration variables; leave otherPALEE_*behavior unchanged unless proven safe to strip. - Effort/Risk/Confidence: S / LOW / HIGH.
- Evidence:
-
P2-05 — Parse
PALEE_ALLOW_INSECURE_CONFIG_DIRas an affirmative value.- Evidence:
src/cli/config.ts:642disables the Windows guard for any non-empty value;:647documents the override as=1. - Impact:
=0or=false, the conventional false spellings, still bypass the profile-location refusal and store the key in a share. - Fix: treat only
1/trueas enabling; every other value keeps the guard active; update the error text if needed. - Effort/Risk/Confidence: S / LOW / HIGH.
- Evidence:
-
P2-06 — Sanitize vault- and config-derived text at the output boundary.
- Evidence:
src/cli/plan.ts:217,src/cli/next.ts:151,169printtopic.titledirectly;src/storage/note-title.ts:52-57strips newlines but not C0/C1 control characters;src/ai/provider.ts:188-196already applies the intended policy. - Impact: a shared or cloned vault whose frontmatter/H1 title contains ANSI/OSC sequences can forge terminal output, hide warnings, or set the clipboard via OSC 52.
- Fix: export one control-character sanitizer and apply it to all vault/config-derived display values at the output boundary, not only provider text.
- Effort/Risk/Confidence: M / LOW / HIGH.
- Evidence:
-
P2-07 — Scope Pages and OIDC permissions to the deploy job.
- Evidence:
.github/workflows/deploy-docs.yml:15-18grantspages: writeandid-token: writeworkflow-wide;:28the build job inherits them while running the third-party VitePress/Mermaid/Katex toolchain;:60-71only the deploy job needs Pages. - Impact: a compromised docs-era dependency executing during build can use the inherited Pages/OIDC credentials.
- Fix: set
contents: readat workflow level and addpages: write/id-token: writeonly to the deploy job. - Effort/Risk/Confidence: S / LOW / HIGH.
- Evidence:
-
P2-08 — Compute the dependency quarantine once in
plan.- Evidence:
src/cli/plan.ts:87callsfindPrerequisiteBlocked, which builds the graph and callsquarantineCyclicTopicsatsrc/application/get-next-topics.ts:141;src/cli/plan.ts:129callsquarantineCyclicTopicsagain. Each pass rebuilds adjacency/Tarjan and can enumerate up to 1000 cycles. - Impact: the most expensive graph operation in the busiest planning command runs twice and allocates three topic maps.
- Fix: return the computed
acyclic/cyclesfrom one pass and pass them to both the gate and the plan sections; keepnext/dashboardbehavior unchanged. - Effort/Risk/Confidence: S / LOW / HIGH.
- Evidence:
-
P2-09 — Scan sessions once per rebuild.
- Evidence:
src/storage/memory.ts:735-772scans allS-*.mdto pick the newest, then:813callsregenerateIndex, which scans the same directory again at:608-659; both read and YAML-parse every file. - Impact: every
session end, draft save/discard andvalidate --fixpays O(2N) session reads/parses; sessions grow without bound. - Fix: collect rows and the newest session in one scan and pass the rows to the index writer (optional parameter; keep the exported
regenerateIndexAPI). - Effort/Risk/Confidence: S / LOW / HIGH.
- Evidence:
-
P2-10 — Cover the cache's later same-size edit branch.
- Evidence:
src/storage/cache.ts:153-165(mtime changed outside the 2 s horizon, same size → re-hash and evict) has no dedicated test;test/storage-cache.test.ts:44-151covers size change, same-size within the horizon, and same-second mtime fallback. - Impact: deleting or breaking the fingerprint comparison keeps the suite green while
plan/nextserve stale status/due/mastery for the life of the process. - Fix: set a cache entry, rewrite the file with equal byte length and a +5 s mtime, assert
get()returnsnull; mirror with equal content to assert a hit. - Effort/Risk/Confidence: S / LOW / HIGH.
- Evidence:
-
P2-11 — Make the Windows directory-fsync test assert the attempt.
- Evidence:
test/storage-atomic-write.test.ts:427-430replaces the refusal assertion withassert.ok(true)on win32. - Impact: the #333 durability fallback can regress on the platform whose
EPERMbehavior it exists for while the suite stays green. - Fix: record that the post-rename directory open/fsync was attempted (the file already tracks directory fds) and assert the attempt; mark any genuinely untestable part as a tracked gap.
- Effort/Risk/Confidence: S / LOW / HIGH.
- Evidence:
-
P2-12 — Lazy-load command handlers.
- Evidence:
bin/palee.ts:15-28statically imports all 14 handlers; measurednode dist/bin/palee.js --versionat 350-380 ms versus ~50 ms for bare Node on this checkout. - Impact: every interactive command pays the full import graph before dispatch.
- Fix: keep Commander static and
await import()each handler inside its.actioncallback; preserve the fatal/exit-code handler andmaybeNotifyUpdatebehavior. - Effort/Risk/Confidence: M / MED / MED.
- Evidence:
P3 — cleanup and smaller contracts
- P3-01 — Serialize config read-modify-write.
src/cli/config.ts:548-550,655-657,741-743load/mutate/save without a lock;saveConfigat:189-235only makes the rename atomic. Concurrent config commands drop each other's fields. Add a config lock or snapshot/mtime check. - P3-02 — Make draft cleanup lock-aware and session-scoped.
src/cli/session.ts:743callsdeleteTopicDrafts;src/storage/memory.ts:1182-1200deletes every same-topic draft, and:1215-1239unlinks without the target lock. Delete only drafts consumed by this session or take each target's lock. - P3-03 — Make the update-check cache write symlink-safe.
src/cli/update-check.ts:313-319useswriteFileSyncon a predictableupdate-check.json; use an exclusive temp file plus rename (orO_NOFOLLOW) and verify the resolved path. - P3-04 — Redact JSON-escaped key spellings in provider errors.
src/ai/provider.ts:188-196masks only the literal secret;:590-597acknowledges that JSON escaping changes the spelling. Mask both the raw andJSON.stringify-escaped forms before printing error/body text. - P3-05 — Extend the INV-29 guard to all socket primitives and
bin/.test/ai-network-boundary.test.ts:30-40misseshttp2,dgram,WebSocket,undici, and scans onlysrc/;:58limits the scan. Add the primitives and an explicit allowlist for the documented npm child process. - P3-06 — Stop loading and hashing full note bodies for read-only commands.
src/storage/loader.ts:346-351reads each body,:374-381retains it, and:405-409hashes it;next/plan/dashboard/progressnever read.content. Add a metadata-only load path. - P3-07 — Avoid double YAML parsing in
validate.src/validation/collect-vault.ts:66-93callsscanNotes(parses atsrc/storage/scanner.ts:274) and thenloadTopics(parses the same bytes atsrc/storage/loader.ts:351);loader.ts:405also hashes injected content and discards it. Share the parsed frontmatter or skip the fingerprint in the snapshot branch. - P3-08 — Stop building
dist/for the coverage run.package.json:40-41runsnpm run buildbeforetest:coverage, but underNODE_V8_COVERAGEthe suites spawnbin/palee.tsvia tsx (test/palee-cli.ts:68-75) and no test readsdist. Keep the build for thenpm testdist path and the release workflow. - P3-09 — Import one pillar-key list from the engine. Six copies:
src/engine/mastery.ts:74,src/application/record-assessment.ts:13,src/cli/validate.ts:101,src/validation/rules/valid-assessment-fields.ts:19,src/validation/rules/valid-topic-mastery.ts:34,src/cli/adopt-undo.ts:67. - P3-10 — Centralize the topic scaffold and owned-key list. Four copies:
src/cli/adopt.ts:408,1406,src/cli/roadmap.ts:276,src/cli/adopt-undo.ts:60,src/validation/rules/valid-review-fields.ts:72. Add one builder and one owned-key set. - P3-11 — Share one batch-scope predicate.
src/cli/adopt.ts:618,629andsrc/cli/adopt-undo.ts:795implement the same include/exclude/tag decision with separate accounting; extract the predicate and keep each command's counters. - P3-12 — Move diagnostic formatting below both layers.
src/engine/sm2.ts:12imports../validation/rules/diagnostic-value, whilesrc/validation/rules/valid-topic-mastery.ts:29imports the engine; relocateformatDiagnosticValueto a neutral module. - P3-13 — Judge non-string
palee_idone way.src/cli/adopt.ts:339treats a truthy non-string as already adopted;:599-610only validates under--auto-chain;src/cli/adopt-undo.ts:204treats it as not a topic;src/storage/loader.ts:353ignores it. Route all scans throughisValidPaleeIdand report one repair path. - P3-14 — Split the god modules.
src/cli/adopt.ts1513 lines,src/engine/toc-chain.ts1330,src/storage/memory.ts1267,src/engine/auto-chain.ts1094,src/cli/roadmap.ts1073. Extract scan/plan/execute phases and split memory into hot/index, sessions, and drafts behind the existing barrel. - P3-15 — Verify the tarball on the local publish path.
package.json:27runs onlynpm run buildinprepublishOnly;scripts/verify-tarball.jsexists but is invoked only byrelease.yml:72. Add the tarball assertion to the local publish path or document the verified-CI-only policy. - P3-16 — Build docs on the Node version CI gates.
.github/workflows/ci.yml:61-64builds docs on Node 24;deploy-docs.yml:41rebuilds on Node 22. Every docs merge builds twice, and the deploy runtime is not covered by PR checks. Use Node 24 in both or deploy the CI artifact. - P3-17 — Include application and validation suites in
test:unit.package.json:33globs only storage/engine/types/smoke; 6 application and 12 validation test files are outside it. Add them or rename the script totest:core. - P3-18 — Make agent instructions discoverable.
agent.md:1is the only 18 KB conventions document; no rootAGENTS.md/CLAUDE.mdexists, andREADME.md:310still says contribution guidelines will be added. Add a pointer file and real clone-to-green steps.
Direction — options, not defects (do not check off as bugs)
- D-01 Named vault profiles or a per-run
--vault. Evidence:bin/palee.ts:42-59tells users to setPALEE_CONFIG_DIRper run to isolate vaults;src/types.ts:382carries onevaultPath. Tradeoff: config precedence must stay backward-compatible; medium effort. - D-02 Publish the application read models. Evidence:
src/index.ts:20-26exports types/engine/storage/validation but notapplication/; ADR-0025:45 anticipates future interfaces callinggetNextTopics/summarizeMastery. Additive, but exported names become compatibility commitments. - D-03 Machine-readable output for mutating commands. Evidence:
README.md:284says the remaining commands are human-only;bin/palee.ts:171,180declare no--jsonforreview/assess;src/application/record-review.ts:111already returns a structured update. Each document needs a stable shape. - D-04 Batch assessment input. Evidence:
bin/palee.ts:180takes one topic plus four score flags;src/application/record-assessment.ts:82computes one update. A--fromfile would need dry-run, confirmation, and exit-1 partial-failure semantics.
Considered and rejected (so they are not re-audited)
- CI never runs
npm test; the dist-entry guard skips under c8 — rejected: thesmoke-installjob builds, packs, installs, and runs the realdiston three OSes, and the coverage-time source launch is deliberate per ADR-0029. - Extract shared adopt/undo helpers — deferred as a duplicate of P1-03 and P2-01; fix the two defects first.
- Roadmap difficulty default diverges from adoption — rejected: both resolve
undefinedtointermediate; the scaffold duplication is real (P3-10) but not a behavior drift. - Dependency audit —
npm auditreports 0 advisories; thevite/mermaid/katex/dompurifyoverrides are confined to the docs toolchain.
Dependency ordering
- P1-04 before P2-09 (both edit
rebuildHotAndIndex/regenerateIndex). - P1-07 before P2-03 if both are selected (both edit
lock.ts). - P1-01 before P1-11 (the timezone tests should pin the capped behavior).
- P1-02 and P1-03 are independent files but share the adoption write-path theme; land both before P3-10/P3-11 refactors.
Not audited
VitePress page content beyond spot checks, architecture/ artifacts, examples/, dist/, full test execution (typecheck/lint only), and dependency provenance beyond npm audit. Standard-depth audit, not deep.
Area
Cross-cutting: Core engine (src/engine/), Storage / vault scanning (src/storage/), Session memory, CLI / bin layer, Tests, Config / migration, AI / Phase 2 (src/ai/), Build / CI, Documentation.
Estimated effort
P1: roughly 2-3 focused days total (all 12 are S). P2: roughly 3-4 days (two M items). P3: roughly 4-6 days, mostly cleanup and refactors. Direction options are separate spikes, not included.
AI acknowledgment
This issue was produced from an AI-assisted, read-only audit at the maintainer's explicit request. Every finding was re-opened and confirmed in source at 24947bc before publication. The maintainer chose full public detail for the security findings after the public-visibility warning. No secret values appear in this report.
- Dominant language
- TypeScript
- Stars
- 1
- Forks
- 0
- Avg merge
- 13h 46m
- Merged PRs (30d)
- 158
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- No contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from Kuldeep2822k/cli
-
feat: comprehensive observability layer (diagnostics + metrics)Possibly taken @Kuldeep2822k claimed this 1 day ago. Opencli core enhancement storage tests
Kuldeep2822k/cli#591 · 1 assignee ·
Maintainers usually reply within 1 day
-
chore priority: low refactor
Difficulty 5/5 Over a week Newbie friendliness 25/100
Kuldeep2822k/cli#548 ·
Maintainers usually reply within 1 day
-
Difficulty 5/5 Over a week Newbie friendliness 25/100
Kuldeep2822k/cli#522 ·
Maintainers usually reply within 1 day
-
bug tests
Difficulty 5/5 Over a week Newbie friendliness 25/100
Kuldeep2822k/cli#504 · 1 comment ·
Maintainers usually reply within 1 day
-
Dependency DashboardOpenci dependencies security
Difficulty 4/5 3-5 days Newbie friendliness 8/100
Kuldeep2822k/cli#463 · 1 comment ·
Maintainers usually reply within 1 day
All issues in Kuldeep2822k/cli
Similar issues
-
community first-timers-only good first issue hacktoberfest help wanted low hanging fruit up-for-grabs
Difficulty 1/5 Under an hour Newbie friendliness 83/100
lingdojo/kana-dojo#33701 · 1 comment · 5 reactions ·
Maintainers usually reply within 1 day
-
tech-debt
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
rookslog/zlibrary-mcp#408 ·
Maintainers usually reply within 1 day
-
mp4box.js — 20-byte `sgpd` box with large `entry_count` causes unbounded loop and heap OOM abortOpen
Difficulty 2/5 1-3 hours Newbie friendliness 77/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
status: needs triage
Difficulty 2/5 1-3 hours Newbie friendliness 64/100
mastra-ai/mastra#29641 · 1 comment ·
Maintainers usually reply within 1 day