WRKLOG-2026-06-03

Summary

Wednesday. Fill summary at end of day.

URGENT - All Domains

Carryover Backlog (CRITICAL)

Task Details Origin Days Status

MSCHAPv2 Migration Report

Report due. 6-sheet Standard Report (exec summary, trend, waves, device detail, stale, policy match). Sheet 6 added 05-14: policy match by protocol for removal planning + anonymous identity validation. Migration window 2026-05-04 to 2026-05-30. ~6,227 devices, 5 waves.

2026-04-17

49

P0 - DUE — run report this week

Abnormal Security — ✅ COMPLETE

CR-2026-05-07-abnormal-read-write. CAB approved 2026-05-12. Implemented successfully 2026-05-13. Read/write enabled for pilot group. Post-deployment validation pending.

2026-05-07

29

✅ IMPLEMENTED — post-validation pending

SIEM QRadar → Sentinel Migration

Lead role. Monad console error RESOLVED 2026-05-12 — secrets configured in CHLA production tenant. ISE secure syslog integration in progress — cert imported, remote logging target configured, streaming errors under investigation. Blocking: DCR not created (Rule ID + Stream Name). Azure private network policy unresolved. Victor + Mauricio action.

2026-04-10

56

P0 - ACTIVE — ISE syslog + DCR blocking

Monad Pipeline Evaluation

Sentinel output connector. Console error resolved. 3 of 6 values configured. Remaining: Endpoint URL (have it), Rule ID + Stream Name (need DCR). ISE Remote Logging Target configured 2026-05-18 — TLS cert imported, secure syslog target created. Streaming errors in Monad console under investigation.

2026-03-11

86

P0 - ACTIVE — ISE integration in progress

Guest Redirect ACL

Guest redirect ACL work needed. Related to Mandiant remediation findings.

2026-05-12

24

P0 - TODO

ISE Patch 10 (CVE-2026-20147 CVSS 9.9)

ISE 3.2 Patch 10. Supersedes Patch 9. 61 days on a CVSS 9.9 — schedule maintenance window. Write CR if needed.

2026-03-12

85

P0 - OVERDUE — schedule immediately

k3s NAT verification

NAT rule 170 for 10.42.0.0/16 pod network - test internet connectivity. 64 days — test this week or defer to Q3.

2026-03-09

88

P0 - BLOCKING — TRIAGE: schedule or defer

Wazuh indexer recovery

Restart pod after NAT confirmed working - SIEM visibility blocked. Blocked by k3s NAT — cannot proceed until above resolved.

2026-03-09

88

P0 - Blocked by k3s

Strongline Gateway VLAN fix

8 devices in wrong identity group (David Rukiza assigned)

2026-03-16

81

P0 - TODO

TCP Clocks deployment

ISE identity group validation, query outputs, comms with team. Active d001 data Apr 22-23.

2026-04-22

44

P0 - ACTIVE

IoT Dr. Kim — recurring

Sleep study devices (Apr 15-16), watches recurrence (Apr 22). 5 incident versions in d001. Validate iPSK enrollment.

2026-04-15

51

P0 - RECURRING

Murus Portae (WAF) — Phase 0

FMC cert expired, ACP returns zero rules. d001: zone map, architecture D2, FMC API reference, ops script.

2026-04-16

50

P0 - INVESTIGATING

Vocera EAP-TLS Supplicant Fix

~10 phones failing 802.1X, missing supplicant config. 61 days — schedule with clinical engineering team.

2026-03-12

85

P1 - TODO — schedule

ISE MnT Messaging Service

Enable "Use ISE Messaging Service for UDP syslogs delivery". 61 days — low risk, schedule with ISE Patch 10 maintenance window.

2026-03-12

85

P2 - BUNDLE with Patch 10

Professional backlog remains critical. Check Days column for priorities.

BLOCKERS — Fix Immediately

Task Details Origin Days Impact

Z Fold 7 Termux

gopass and SSH not working

2026-03-10

58

BLOCKER — Cannot access passwords on mobile

gopass v3 organization

Inconsistent structure, poor key-value usage

2026-03-20

48

Inefficient password management, no aggregation

Git history scrub — sensitive personal terms

Plaintext references to personal legal matters in committed worklogs (WRKLOG-2026-03-14, WRKLOG-2026-04-18). Forward-fixed but old commits still contain strings. Requires git filter-repo + force-push. See runbook below.

2026-04-22

15

SECURITY — sensitive terms in public git history

Runbook: Git History Scrub (d000 Personal Terms)

Problem: Two committed worklogs contained plaintext references to personal legal matters. The files have been edited (forward-fix), but git history retains the original text in prior commits.

Affected commits: Any commit touching these files:

# Identify affected commits
git log --oneline -- \
  docs/modules/ROOT/pages/2026/03/WRKLOG-2026-03-14.adoc \
  docs/modules/ROOT/pages/2026/04/WRKLOG-2026-04-18.adoc

Scrub procedure:

# 1. BEFORE: Full backup of the repo
cp -a ~/atelier/_bibliotheca/domus-captures ~/atelier/_bibliotheca/domus-captures.bak

# 2. Install git-filter-repo (if not present)
# Arch: pacman -S git-filter-repo
# pip: pip install git-filter-repo

# 3. Create expressions file for replacement
cat > /tmp/scrub-expressions.txt << 'EXPR'
regex:(?i)divorce==[REDACTED]
regex:(?i)dissolutio(?!n\.adoc\.age)==[REDACTED-LEGAL]
regex:(?i)iliana==[REDACTED-NAME]
regex:(?i)angulo-arreola==[REDACTED-NAME]
regex:legal-divorce-notes\.age==legal-notes.age
regex:1099-NEC-iliana==1099-NEC
EXPR

# 4. Verify before (dry run — count matches in history)
git log -p --all -S 'divorce' -- '*.adoc' | grep -c 'divorce' || echo "0 matches"
git log -p --all -S 'iliana' -- '*.adoc' | grep -c 'iliana' || echo "0 matches"

# 5. Run filter-repo (DESTRUCTIVE — rewrites all commit hashes)
git filter-repo --replace-text /tmp/scrub-expressions.txt --force

# 6. Verify after
git log -p --all -S 'divorce' -- '*.adoc' | grep -c 'divorce' || echo "0 matches — CLEAN"
git log -p --all -S 'iliana' -- '*.adoc' | grep -c 'iliana' || echo "0 matches — CLEAN"

# 7. Re-add remotes (filter-repo removes them)
git remote add origin git@github.com:<user>/domus-captures.git
# Add any other remotes (Gitea, etc.)

# 8. Force-push to all remotes (DESTRUCTIVE — overwrites remote history)
git remote | xargs -I{} git push {} main --force

# 9. Clean up
rm /tmp/scrub-expressions.txt
rm -rf ~/atelier/_bibliotheca/domus-captures.bak  # only after verifying

Post-scrub checklist:

  • Backup created before running

  • git filter-repo installed

  • Expressions file reviewed — no false positives (e.g., Don Quijote "Angulo el Malo" is in segunda-parte/texto/texto-011.adoc — the regex targets angulo-arreola specifically to avoid this)

  • Dry-run counts match expectations

  • Filter-repo executed

  • Post-scrub verification shows 0 matches

  • Remotes re-added

  • Force-pushed to all remotes

  • Cloudflare Pages rebuild verified

  • Local clones on other machines re-cloned or git fetch --all && git reset --hard origin/main

  • Backup removed

URGENT - Requires Immediate Action

Item Details Deadline Status Impact

Housing Search

Granada Hills area - apartments/rooms

TBD

In Progress

Quality of life, commute

2025 Tax — IRS Transcript Review

MFJ filed 2026-04-22. Pull IRS Return Transcript to verify contents. Consult attorney re: Form 8857 (Innocent Spouse Relief). Details in encrypted case file.

Before attorney meeting

In Progress

Financial — liability exposure. See data/d000/personal/dissolutio/

Rack Relocation

Physical move of server rack. CR written: CR-2026-04-18 (pending in infra-ops). Borg backup completed. VM XML dumps, switch save, shutdown/startup procedure documented.

TBD

Pending

Infrastructure downtime — all services offline during move

D000 Legal Planning

Encrypted case file: data/d000/personal/dissolutio/. Open: dissolutio-open. Close: dissolutio-close. 19 partials + assembler. PDF build for attorney handoff. Critical deadline: Jan 2029.

Before Jan 2029

Active — escalating

Life transition — see case file for details

Credit Report Review

Pull reports from all 3 bureaus via annualcreditreport.com. Verify no unknown joint accounts or debts. Credentials in gopass: v3/personal/finance/credit/annual_credit_report

TBD

In Progress

Financial discovery — FL-142 preparation

Gopass Security Audit

Rotate passwords on shared/known accounts. Add 2FA backup codes to v3/personal/recovery/. Create missing government entries (IRS, SSA, VA, DMV). Add last_login field to active entries.

TBD

Pending

Digital security — pre-filing preparation

Subscription Audit

Download 3 months bank/CC statements (Chase, NFCU, USAA). Identify all recurring charges. Cancel unnecessary. Document active subscriptions for FL-150.

TBD

Pending

Financial — expense documentation

401(k) Enrollment

Enroll in CHLA 401(k) immediately. Post-separation contributions are 100% separate property. Reduces gross income for support calculations. Max 2026: $23,500/yr.

In progress (started 5/4)

In Progress

Financial — support calculation + retirement

URGENT — Performance Review Certifications

Certification Provider Deadline Status Impact

CISSP

ISC² — Certified Information Systems Security Professional

July 12, 2026

ACTIVE — Week 2 of 10 (Project)

Required for performance review. 10-week accelerated plan.

RHCSA 9

Red Hat Certified System Administrator

Q3 2026

ACTIVE — 21-phase curriculum (Project)

After CISSP. Required for performance review.

CISSP: 41 days remaining (exam July 12). Domain 1 study in progress. Schedule exam today (06-01).

Early Morning - 5:30am

Regex Training (CRITICAL CARRYOVER)

  • Session 3 - Character classes, word boundaries

  • Practice drills from regex-mastery curriculum

  • Status: 52 days carried over (since 2026-03-16) — CRITICAL

Regex training continues to slip. This is the foundation for all CLI mastery.

Daily Notes

Triage Status

Item Status Destination

Schedule CR implementation: Guest ACL Hardening (approved 06-02)

Action needed

Coordinate with Tony Sun (switch ACL) + David Rukiza (validation)

Schedule CR implementation: Anonymous Identity Test (approved 06-02)

Action needed

Coordinate with Argam (AirWatch profile push)

Tube System Re-run (iTrack 3528165)

Carry-forward from 06-01

Scripts fixed, 15 MACs confirmed NOT IN ISE — re-run pending

Alex Pena — ISE device verification

Pending

Run ERS API + DataConnect checks on his claimed device adds

ISE Annual Cert Renewal — CSR generation

Ready

51 days to expiry (July 24). DigiCert CA. CSR config + commands in d001.

Linux Inventory Discovery — run queries

Pending

SQL ready: dc-run-sql data/d001/projects/linux-research/sql/linux-inventory-summary.sql

Abnormal ESA→EOP Policy Review — follow-ups

Active

DKIM disabled (investigate), AutoForwarding On (fix), pilot→full org rollout

Android Handheld Scanners — ISE policy for shared devices

June 8 deadline (5 days)

Argam needs MDM profile before vendor onsite. ISE auth/authz policy needed.

ESA Message Trace — policy divergence investigation

Active

ESA-Bypass skipping blacklist/sender group enforcement

Getwell iPads — iPSK onboard (Argam/Spectrum IoT)

Done

2 devices added to iPSK workflow. 4C:B9:10:9F:05:9F, C4:12:34:2D:F3:14

Monad Pipeline — weekly sync (William Cox)

Meeting

FMC/ISE kinks, add Cisco network sources, begin transforms

ESA Mail Flow Policy Divergence — Five Canons Analysis

Dispositio

This investigation applies the Five Canons of rhetoric as an analytical framework — not for persuasion, but for structured technical reasoning.

I. Inventio (Discovery — What is observed)

Identical messages are handled differently by ESA depending on the mail path:

  • Standard ESA path → message blocked (blacklist / policy enforcement)

  • ESA-Bypass path → same message delivered

Both cases show:

  • Comparable sender IP

  • SBRS in gray range (~2.6)

  • No obvious content delta

The divergence is in policy application, not message content.

II. Dispositio (Arrangement — How the problem is structured)
Phase Method

Data extraction

ESA message tracking PDFs → pdftotext

Normalization

Remove noise, align format → sed

Signal isolation

Policy, SBRS, sender group, action → grep

Comparative analysis

Diff between flows → diff -u

This allows direct correlation of: listener → policy → sender group → action.

III. Elocutio (Style — High-signal output)

Output reduced to decision-determining fields only:

  • Sender IP — confirms same source

  • SBRS — Talos reputation score

  • Listener — ESA-Bypass vs standard

  • Mail Policy — which rule set applied

  • Sender Group — Trusted / Unknown / Blacklisted

  • Action / Verdict — Delivered vs Dropped

  • Blacklist hits

IV. Memoria (Reproducibility — Codified workflow)

The workflow is terminal-native and repeatable:

  • pdftotext → extraction

  • sed → normalization

  • grep → signal filtering

  • diff → comparison

  • Process substitution for one-liner execution

V. Pronuntiatio (Conclusion — What it means)

Findings:

  • ESA-Bypass omits enforcement present in standard ESA

  • Blacklist and sender group classification not applied in bypass path

  • SBRS alone does not explain delivery behavior

Implications for migration:

  • Aligning all listeners before ESA decommission is prerequisite

  • ESA-Bypass scope must be restricted to trusted/internal systems

  • This evidence supports the Abnormal policy review deliverable in d001


ESA Message Trace — Reproducible Workflow

Step 1 — Extract text from ESA PDFs
pdftotext "jv_esa_message_tracking_details (60).pdf" normal.txt
pdftotext "sc_bypassesa__message_tracking_details (61).pdf" bypass.txt
Step 2 — Normalize (remove noise)
sed -E '/^$/d;/^Page/d' normal.txt > normal.clean
sed -E '/^$/d;/^Page/d' bypass.txt > bypass.clean
Step 3 — Extract high-signal fields
grep -Ei 'Sender|IP|SBRS|Policy|Listener|Action|Verdict|Spam|Blacklist' normal.clean > normal.sig
grep -Ei 'Sender|IP|SBRS|Policy|Listener|Action|Verdict|Spam|Blacklist' bypass.clean > bypass.sig
Step 4 — Diff signal only
diff -u normal.sig bypass.sig
Step 5 — One-liner (process substitution — no temp files)
diff -u \
  <(pdftotext "jv_esa_message_tracking_details (60).pdf" - \
    | sed -E '/^$/d;/^Page/d' \
    | grep -Ei 'IP|SBRS|Policy|Listener|Action|Verdict|Blacklist') \
  <(pdftotext "sc_bypassesa__message_tracking_details (61).pdf" - \
    | sed -E '/^$/d;/^Page/d' \
    | grep -Ei 'IP|SBRS|Policy|Listener|Action|Verdict|Blacklist')
Process substitution <(cmd) creates virtual files from command output — no temp files, no cleanup. pdftotext …​ - outputs to stdout instead of a file. This is the pattern to reach for when comparing two command outputs.
Expected Finding
Normal ESA:
  Listener    : IncomingMail
  Policy      : Default
  SenderGroup : Blacklisted
  Action      : Dropped

ESA-Bypass:
  Listener    : ESA-Bypass
  Policy      : BypassPolicy
  SenderGroup : Unknown
  Action      : Delivered
Root Cause

ESA-Bypass is not enforcing:

  • Blacklists

  • Sender group classification

  • Anti-spam scanning

The standard ESA path applies these controls correctly. The divergence is in policy application, not message content or SBRS score.

  • Align blacklist and sender group enforcement across all listeners

  • Restrict ESA-Bypass scope to trusted/internal systems only

  • Validate before migration cutover — prerequisite for ESA decommission

Reuse Pattern
Generic: compare any two PDF exports
diff -u \
  <(pdftotext "file-a.pdf" - | sed -E '/^$/d' | grep -Ei 'PATTERN') \
  <(pdftotext "file-b.pdf" - | sed -E '/^$/d' | grep -Ei 'PATTERN')
Generic: compare any two command outputs
diff <(command-a) <(command-b)

ISE Certificate — CSR Generation

ISE Certificate — Generate CSR Today

Expiry: July 24, 2026 (51 days)
CA: DigiCert (GeoTrust TLS RSA CA G1)
Current cert: CN=access2.ise.chla.org, SAN=*.ise.chla.org, 2048-bit
New cert: Same CN/SAN, upgrading to 4096-bit

Step 1 — Create config file
cat > /tmp/ise-cert-renewal.cnf << 'EOF'
[req]
default_bits       = 4096
prompt             = no
default_md         = sha256
req_extensions     = req_ext
distinguished_name = dn

[dn]
C  = US
ST = California
L  = Los Angeles
O  = Childrens Hospital Los Angeles
OU = Information Security
CN = access2.ise.chla.org

[req_ext]
subjectAltName = @alt_names
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth, clientAuth

[alt_names]
DNS.1 = access2.ise.chla.org
DNS.2 = *.ise.chla.org
EOF
Step 2 — Generate key + CSR
openssl genrsa -out /tmp/ise-cert-renewal.key 4096

openssl req -new \
  -key /tmp/ise-cert-renewal.key \
  -config /tmp/ise-cert-renewal.cnf \
  -out /tmp/ise-cert-renewal.csr
Step 3 — VERIFY before submitting
# CN must be access2.ise.chla.org — NOT *.ise.chla.org
openssl req -in /tmp/ise-cert-renewal.csr -noout -subject -text | grep -E 'Subject:|DNS:'
Expected output
Subject: C=US, ST=California, L=Los Angeles, O=Childrens Hospital Los Angeles, OU=Information Security, CN=access2.ise.chla.org
            DNS:access2.ise.chla.org, DNS:*.ise.chla.org
If CN shows *.ise.chla.org — STOP. Delete and regenerate. Windows 802.1X will reject it (CSCuh22029).
Step 4 — Secure the private key
# Copy to d001 encrypted storage
cp /tmp/ise-cert-renewal.key data/d001/projects/ise-annual-cert-renewal/certs/ise-cert-renewal-2026.key
cp /tmp/ise-cert-renewal.csr data/d001/projects/ise-annual-cert-renewal/csr/ise-cert-renewal-2026.csr

# Encrypt the private key
rm -f data/d001/projects/ise-annual-cert-renewal/certs/ise-cert-renewal-2026.key.age
encrypt-file data/d001/projects/ise-annual-cert-renewal/certs/ise-cert-renewal-2026.key

# Clean up /tmp
rm -f /tmp/ise-cert-renewal.key /tmp/ise-cert-renewal.csr /tmp/ise-cert-renewal.cnf

# Verify
ls -la data/d001/projects/ise-annual-cert-renewal/certs/*.age
ls -la data/d001/projects/ise-annual-cert-renewal/csr/*.csr
Step 5 — Submit to DigiCert
  • CSR verified: CN = access2.ise.chla.org, SAN = *.ise.chla.org

  • Private key encrypted in d001

  • CSR submitted to DigiCert: method (portal / email)

  • Explicitly requested CA does NOT auto-add wildcard to CN

  • Expected turnaround: days

Results
  • CSR generated: yes/no

  • Verification passed: yes/no

  • Submitted to CA: date

  • Key secured in d001: yes/no

Monad Pipeline — Weekly Sync

Monad Pipeline — Weekly Sync

Date: 2026-06-03
From: William Cox (Teams)
Note: Will joined late — on DR call with Andrew and Sarah

Agenda (William’s priorities)
Priority Item Status

1

Resolving kinks with added log sources (FMC, ISE)

Active

2

Confirming we can add further sources (Cisco network sources)

Pending validation

3

Adding further log sources

Planning

4 (Important)

Beginning transforms — flexing what Monad does for us

Next phase

Current Log Source Status

Based on existing documentation (partials/projects/monad-evaluation/log-sources.adoc):

Source Protocol In Monad? Kinks?

ISE RADIUS (pPAN/sPAN, pMNT/sMNT, 4 PSNs)

Syslog

confirm

William says kinks — what specifically?

FMC / FTD Sensors

Syslog

confirm

William says kinks — what specifically?

Cisco Network (switches, routers, WLC)

Syslog

not yet

Next to add per agenda item 2-3

ASA VPN

Syslog

confirm

Microsoft Defender / 365

Native API

confirm

Questions to Capture During Meeting
  • What are the specific kinks with FMC log source? (parsing? connectivity? volume?)

  • What are the specific kinks with ISE log source? (which ISE services? RADIUS? TACACS? both?)

  • Which Cisco network sources are next? (switches first? WLC? routers?)

  • What transforms does William want to start with? (filtering low-value? OCSF normalization? enrichment?)

  • Is Sentinel receiving anything yet, or is everything still in staging?

  • DR discussion overlap — does DR affect Monad pipeline availability?

Transforms — What to Prepare

William flagged transforms as the next phase. Based on existing work (monad-sdk/ partials):

Transform Type What It Does

Filtering

Drop low-value logs before Sentinel ingestion → cost reduction

Normalization (OCSF)

Convert vendor-specific formats to Open Cybersecurity Schema Framework

Enrichment

Add context (GeoIP, threat intel, asset metadata) before storage

Routing

Critical → Sentinel (real-time), Bulk → Cold Storage (S3)

Existing transform docs:

  • ISE transforms: partials/projects/monad-sdk/ise-transforms.adoc

  • FTD transforms: partials/projects/monad-sdk/ftd-transforms.adoc

  • jq patterns: partials/projects/monad-sdk/jq-patterns.adoc

  • Training: pages/education/training/monad/transforms.adoc

API Key Management — Proposal

Monad will provide a shell script to create pipelines and add devices via API key. Security considerations:

Concern Mitigation

Key at rest

Encrypted with age. Never in plaintext on disk. Never committed to source control.

Key at runtime

Loaded into environment variable only: $MONAD_API_KEY. Script consumes the var, never the value.

Key in script

The vendor script must NOT hardcode the key. If it does, we rewrite it.

Key rotation

Establish rotation cadence with Monad. Scoped keys preferred — one per function, not one for everything.

Key access

Only our team. If Monad support needs access for troubleshooting, separate key with limited scope.

Audit

Log every API call. Key usage traceable to operator.

What to say in the meeting

«I want to make sure the API key is encrypted at rest, loaded at runtime only, and never committed to source control. I’ll own the key lifecycle — storage, rotation, access audit. The script should consume it from an environment variable, not a config file.»

Implementation (internal — don’t share with vendor)
# Key stored in gopass, loaded via dsource
dsource d001 dev/monad    # loads MONAD_API_KEY

# Or age-encrypted one-off
MONAD_API_KEY=$(age -d -i ~/.age/identities \
  data/d001/projects/monad-pipeline/certs/monad-api-key.txt.age)
export MONAD_API_KEY

# Script uses the var
./monad-create-pipeline.sh --source switches --key "$MONAD_API_KEY"
Script review checklist (when received from Monad)
# Read every line first
less monad-pipeline-setup.sh

# Check what it calls
grep -E 'curl|wget|ssh|scp|eval|exec' monad-pipeline-setup.sh

# Check for hardcoded credentials
grep -Ei 'key|token|pass|secret|auth' monad-pipeline-setup.sh

# Check for external downloads
grep -Ei 'http|ftp|download|raw\.' monad-pipeline-setup.sh

# Check what it writes/modifies
grep -E '>/|>>|tee|mv|cp|rm|install' monad-pipeline-setup.sh
ASA Firewall — Add via Monad GUI

The ASA firewall log source needs to be added through the Monad web GUI, not the API script.

Field Value

Source Type

Syslog (ASA sends syslog natively)

Source Name

ASA-FW or org naming convention

Source IP

ASA management IP — confirm

Protocol

UDP 514 or TCP 514 (confirm with network team)

Log Format

Cisco ASA syslog (auto-detected by Monad)

Destination

Monad collector IP/port

Expected Volume

MEDIUM (VPN + firewall events)

ASA syslog config (if not already forwarding)
! On the ASA
logging enable
logging host <interface> <monad-collector-ip> udp/514
logging trap informational
logging device-id hostname

! Verify
show logging
If the ASA is already forwarding syslog to QRadar, you may need to add Monad as a second destination during migration — don’t remove QRadar until Monad is validated.
Questions for the Monad GUI setup
  • Does Monad auto-detect ASA syslog format?

  • Does Monad support dual syslog destinations (ASA → QRadar + Monad simultaneously)?

  • What Monad collector IP/port do we point the ASA to?

  • Is there a Monad parser specifically for ASA events (failover, VPN, ACL hits)?

My Action Items
Action Owner Due

Review Monad pipeline script when received — verify no hardcoded keys

Evan

When received

Set up gopass/dsource entry for MONAD_API_KEY

Evan

Before first script run

Add ASA firewall via Monad GUI

Evan

This week

Test one switch pipeline before batch deployment

Evan

After script review

EOP Anti-Spam Policy Review — BCL + SCL

EOP Anti-Spam Policy Review — BCL + SCL

BCL (Bulk Complaint Level) — Sender Reputation

BCL measures how "bulky" a sender is based on complaint rate across all O365 tenants. Microsoft assigns it per sender, not per message.

Lower threshold = MORE filtering (stricter). Higher = LESS filtering (lenient).

BCL What it means Example senders

0

Not bulk — regular sender

Direct person-to-person email

1–3

Bulk, few complaints

LinkedIn, DocuSign, Zoom, Microsoft notifications

4–6

Bulk, mixed complaints — gray zone

Marketing you may or may not want. Phishing hides here.

7–9

Bulk, high complaints

Unsolicited marketing, newsletter spam

Current BCL Thresholds (from 06-02 audit)
Policy Threshold Assessment

Default

7

Too lenient — only worst bulk filtered

Test Policy

7

Same — lenient

Standard Preset

6

Slightly stricter

Abnormal Best Practices

5

Recommended for healthcare

Anti-Spam-Inb-CHLA

7

Too lenient

Team Discussion: BCL Threshold

The team wants to lower to 1. Impact analysis:

Threshold What gets quarantined Operational impact

5 (recommended)

Phishing-disguised-as-bulk, gray-zone marketing

Few false positives. Manageable.

4

Above + some legit marketing

Occasional false positive. Acceptable for healthcare.

3

Above + most vendor newsletters

Weekly user complaints. Frequent quarantine releases.

1 (team proposal)

Everything with BCL > 0 — nearly all bulk

LinkedIn, DocuSign, Zoom, fax2mail, medical journals, vendor alerts, conference registrations, KidsX/AVIA executive emails, Cisco/Microsoft security advisories ALL quarantined. Help desk becomes email release desk. Hundreds of messages daily.

Dispositio — What to say

Exordium:

«The threshold is a cutoff — anything at or above that number gets treated as spam. Lowering from 7 to 5 catches more, not less. Going to 1 quarantines everything that isn’t direct person-to-person.»

Confirmatio:

«At BCL 1, these get quarantined: LinkedIn, DocuSign, Zoom invitations, medical journal subscriptions, vendor security advisories, fax2mail, KidsX executive emails. Someone needs to review and release hundreds of quarantined messages daily.»

Peroratio:

«Let’s set to 5 today — Abnormal’s recommendation. Monitor one week. If phishing gets through at 5, tighten to 4. Validate each step. Going straight to 1 isn’t tightening security — it’s turning off bulk email.»

If they insist on 1:

«I need that decision in writing with an owner for the quarantine review queue.»

SCL (Spam Confidence Level) — Per-Message Score

SCL measures how "spammy" a specific message is based on content analysis. EOP assigns it per message.

SCL Meaning What EOP does

-1

Trusted — skip spam filtering

Internal, safe senders, transport rule override

0

Not spam — clean

Deliver

1–4

Low confidence spam

Deliver (usually)

5–6

Spam

Action from SpamAction

7–8

High confidence spam

Action from HighConfidenceSpamAction

9

Highest confidence

Always quarantine/reject

Current SCL Actions (from 06-02 audit) — THE BIGGER PROBLEM
Policy SpamAction (SCL 5-6) HighConfSpamAction (SCL 7-8) Assessment

Default

AddXHeader

AddXHeader

CRITICAL — does nothing. Spam delivered with invisible stamp.

Test Policy

Quarantine

Quarantine

Good — but scoped to test users only

Standard Preset

MoveToJmf

Quarantine

Good

Abnormal Best Practices

MoveToJmf

MoveToJmf

Good — but pilot group only

Anti-Spam-Inb-CHLA

Quarantine

Quarantine

Good — but check scope

The Default policy uses AddXHeader for BOTH spam and high-confidence spam. This means anyone NOT in a scoped policy (Abnormal pilot, CHLA test, Standard Preset) receives no real spam filtering. Spam hits their inbox with a hidden header nobody sees.
What to tell the team about SCL

«We’re debating BCL thresholds for bulk marketing, but the Default anti-spam policy has a bigger gap. It uses AddXHeader for spam — that means spam gets delivered to inboxes with a stamp nobody can see. We need to change the Default to MoveToJmf for spam and Quarantine for high-confidence spam. Otherwise most users have no real spam protection.»

Policy Change From → To Priority

All policies

BulkThreshold

7 → 5

P1

Default

SpamAction

AddXHeader → MoveToJmf

P0 — critical

Default

HighConfidenceSpamAction

AddXHeader → Quarantine

P0 — critical

Abnormal policies

Scope

Pilot group → full org

P1

PowerShell — Verify and Change
Check current state
Get-HostedContentFilterPolicy | Format-List Name, SpamAction, HighConfidenceSpamAction, BulkThreshold, BulkSpamAction
Fix Default policy SCL actions (P0)
# Set-HostedContentFilterPolicy -Identity "Default" -SpamAction MoveToJmf -HighConfidenceSpamAction Quarantine
Set BCL threshold to 5 across all policies
# Get-HostedContentFilterPolicy | Set-HostedContentFilterPolicy -BulkThreshold 5
Verify after changes
Get-HostedContentFilterPolicy | Format-List Name, SpamAction, HighConfidenceSpamAction, BulkThreshold
The Set- commands are commented out. Uncomment and run only after team approval. These are production changes.
Monitoring After Changes
Check quarantine volume (daily for first week)
Get-QuarantineMessage -StartReceivedDate (Get-Date).AddDays(-1) -EndReceivedDate (Get-Date) |
  Group-Object Type | Select-Object Name, Count | Format-Table -AutoSize
Check for false positives (legit senders quarantined)
Get-QuarantineMessage -StartReceivedDate (Get-Date).AddDays(-1) -EndReceivedDate (Get-Date) |
  Where-Object { $_.SenderAddress -match 'linkedin|docusign|zoom|cisco|microsoft|aamc' } |
  Select-Object ReceivedTime, SenderAddress, Subject | Format-Table -AutoSize

Monad jq ↔ GJSON Translation Reference

jq ↔ GJSON — Translation Reference

The Workflow: Terminal First, GUI Second
Step What

1. Capture raw log

tcpdump or copy from Monad pipeline logs → save as .json

2. Prototype in terminal

jq — iterate until the transform is right

3. Translate to GJSON

Use this reference to convert jq expressions to Monad GUI paths

4. Deploy in Monad

Apply via GUI (GJSON) or API (jq transform)

5. Validate

Compare Monad output against your jq output — must match

Field Access
Operation jq (terminal) GJSON (Monad GUI)

Simple field

.username

username

Nested field

.event.src.ip

event.src.ip

Deep nested

.ise.policy.authorization.profile

ise.policy.authorization.profile

Array first element

.[0] or .events[0]

0 or events.0

Array length

.events | length

events.#

Array last element

.events[-1]

events.# (no direct equivalent — use index)

All values of key in array

[.events[].ip]

events.#.ip

Nested in array

.events[].src.ip

events.#.src.ip

Filtering
Operation jq (terminal) GJSON (Monad GUI)

Equals

select(.status == "active")

#(status=="active")

Not equals

select(.status != "inactive")

#(status!="inactive")

Greater than

select(.severity > 3)

#(severity>3)

Less than

select(.port < 1024)

#(port<1024)

Pattern match

select(.name | test("admin.*"))

#(name%"admin*")

Not pattern

select(.name | test("test.*") | not)

#(name!%"test*")

Multiple conditions

select(.severity > 3 and .action == "deny")

No direct equivalent — use chained transforms or jq

Transforms — jq to Monad GUI
What jq (prototype in terminal) Monad GUI transform

Drop low-value logs

select(.severity != "info")

Type: drop_record_where_value_eq
Key: severity
Value: info

Drop successful auths

select(.ise.auth_result != "PASSED")

Type: drop_record_where_value_eq
Key: ise.auth_result
Value: PASSED

Rename field

.source_ip = .src.ip | del(.src.ip)

Type: rename_key
Old: src.ip
New: source_ip

Add static field

. + {"destination": "sentinel"}

Type: add
Key: destination
Value: sentinel

Conditional tagging

if .event_type == "auth_failure" then
  . + {"mitre": "T1078"}
else . end

Type: create_key_value_if_key_value
Condition Key: event_type
Condition Value: auth_failure
New Key: mitre
New Value: T1078

Route by severity

if .severity == "critical" then
  . + {"route": "sentinel"}
else
  . + {"route": "s3"}
end

Requires jq transform (too complex for GJSON)

Extract and flatten

{
  user: .user.name,
  ip: .endpoint.ip,
  result: .ise.auth_result,
  policy: .ise.policy_set
}

Requires jq transform (restructuring)

OCSF normalization

{
  class_uid: 3002,
  activity_id: (if .ise.auth_result == "PASSED" then 1 else 2 end),
  actor: { user: { name: .user.name }},
  src_endpoint: { ip: .endpoint.ip, mac: .endpoint.mac },
  dst_endpoint: { ip: .ise.node_ip },
  severity_id: (if .severity == "critical" then 4 elif .severity == "high" then 3 else 1 end),
  status_id: (if .ise.auth_result == "PASSED" then 1 else 2 end),
  time: .timestamp
}

Requires jq transform (full restructuring + conditionals)

When to Use Which
Tool Context Use When

jq (terminal)

Prototype + validate

Always start here. Test with real log data before deploying anything.

GJSON (Monad GUI)

Simple transforms in production

Drop by field value, rename, add static field, simple conditionals. William and the team can see and modify these.

jq (Monad API)

Complex transforms in production

Multi-condition routing, OCSF normalization, restructuring, MITRE tagging with logic. Only you will maintain these.

Terminal Prototype Workflow
Step 1 — Get a sample log
# From Monad pipeline logs, or capture directly
# Save as sample.json for testing
cat > /tmp/ise-sample.json << 'EOF'
{
  "timestamp": "2026-06-03T10:30:00Z",
  "severity": "high",
  "event_type": "auth_failure",
  "user": {"name": "jdoe", "domain": "CHLA"},
  "endpoint": {"mac": "AA:BB:CC:DD:EE:FF", "ip": "10.50.10.100"},
  "ise": {
    "policy_set": "Wired_802.1X_Closed",
    "auth_result": "FAILED",
    "failure_reason": "Certificate validation failed"
  }
}
EOF
Step 2 — Prototype transforms
# Filter: only failures
jq 'select(.ise.auth_result == "FAILED")' /tmp/ise-sample.json

# Add routing tag
jq '. + {"route": "sentinel", "mitre": "T1078"}' /tmp/ise-sample.json

# Flatten for Sentinel
jq '{
  user: .user.name,
  ip: .endpoint.ip,
  mac: .endpoint.mac,
  result: .ise.auth_result,
  reason: .ise.failure_reason,
  policy: .ise.policy_set,
  time: .timestamp,
  route: "sentinel"
}' /tmp/ise-sample.json

# OCSF normalize
jq '{
  class_uid: 3002,
  activity_id: 2,
  actor: {user: {name: .user.name, domain: .user.domain}},
  src_endpoint: {ip: .endpoint.ip, mac: .endpoint.mac},
  severity_id: 3,
  status_id: 2,
  message: .ise.failure_reason,
  time: .timestamp
}' /tmp/ise-sample.json
Step 3 — Compare after deploying to Monad
# Your jq output
jq '<transform>' /tmp/ise-sample.json > /tmp/expected.json

# Monad's output (from pipeline logs)
cat /tmp/monad-output.json > /tmp/actual.json

# Diff
diff <(jq -S '.' /tmp/expected.json) <(jq -S '.' /tmp/actual.json)
ASA-Specific Transforms (for the firewall log source)
# ASA syslog → structured JSON (what Monad receives)
# Example raw ASA syslog:
# %ASA-6-302013: Built inbound TCP connection 12345 for inside:10.1.1.50/45678 to outside:8.8.8.8/443

# jq transform for ASA connection logs
jq '{
  action: (if .message | test("Built") then "allow" elif .message | test("Teardown") then "close" else "deny" end),
  src_ip: (.message | capture("for \\w+:(?<ip>[\\d.]+)") | .ip),
  dst_ip: (.message | capture("to \\w+:(?<ip>[\\d.]+)") | .ip),
  protocol: (if .message | test("TCP") then "tcp" elif .message | test("UDP") then "udp" else "other" end),
  severity: .severity,
  route: (if .severity == "critical" or .severity == "high" then "sentinel" else "s3" end)
}'

# Drop informational connection logs (high volume, low value)
jq 'select(.severity != "info" and .severity != "debug")'

# Keep only denied connections (security-relevant)
jq 'select(.message | test("Deny|denied|Drop|Teardown"))'

Getwell iPads — iPSK Onboard

Getwell iPads — iPSK Endpoint Onboard

Date: 2026-06-03 10:32 (Teams)
Requestor: Argam
Project: Getwell / Spectrum IoT
Policy: iPSK workflow
Status: Devices added

Request
Hey Evan,

I'm trying to onboard these as part of the Getwell/Spectrum project per Argam.
Not sure what ISE group to add them too

N54850 - H9HFFTGEQ1GG      4cb9109f059f
N56426 - F435M24LC3        c412342df314
Devices
# Asset Serial MAC

1

N54850

H9HFFTGEQ1GG

4C:B9:10:9F:05:9F

2

N56426

F435M24LC3

C4:12:34:2D:F3:14

iPSK Workflow Entries
Device 1
association: "Getwell iPads"
device-mac: "4C:B9:10:9F:05:9F"
description: "2026-06-03 10:37 - Per Argam request, Getwell Spectrum IoT Project"
fullname: "getwell-ipads"
email: "getwell-ipads.chla.usc.edu"
Device 2
association: "Getwell iPads"
device-mac: "C4:12:34:2D:F3:14"
description: "2026-06-03 10:37 - Per Argam request, Getwell Spectrum IoT Project"
fullname: "getwell-ipads"
email: "getwell-ipads.chla.usc.edu"
Verification
Check both MACs in ISE (ERS API)
dsource d001 dev/network/ise

curl -sk "https://$ISE_PAN_FQDN:$ISE_ERS_PORT/ers/config/endpoint?filter=mac.EQ.4C:B9:10:9F:05:9F" \
  -u "$ISE_API_USER:$ISE_API_PASS" \
  -H "Accept: application/json" | jq '.SearchResult.total'

curl -sk "https://$ISE_PAN_FQDN:$ISE_ERS_PORT/ers/config/endpoint?filter=mac.EQ.C4:12:34:2D:F3:14" \
  -u "$ISE_API_USER:$ISE_API_PASS" \
  -H "Accept: application/json" | jq '.SearchResult.total'
Batch check
cat > /tmp/getwell-macs.txt << 'EOF'
4C:B9:10:9F:05:9F
C4:12:34:2D:F3:14
EOF

source scripts/ise-check-macs.sh /tmp/getwell-macs.txt
Notes
  • iPSK workflow — pre-shared key per device based on MAC, no 802.1X

  • Target: Getwell patient entertainment iPads on IoT VLAN

  • Verify with Argam that devices are also enrolled in Intune/MDM

  • Both devices need correct VLAN assignment after authentication

Ad-Hoc Requests

Ad-Hoc Requests

Capture walk-ups, Teams pings, and unplanned work here.

*

Terminal Commands and Tools

File Discovery + Inspection Workflow

Find → Open in nvim
# Command substitution — open first match
nvim $(find docs/ -name '*2026-06-03*' -type f | head -1)

# Open ALL matches in one nvim session (buffers)
nvim $(find docs/ -name '*2026-06-03*' -type f)

# -exec + variant — opens all in one nvim
find docs/ -name '*2026-06-03*' -type f -exec nvim {} +

# Safe (handles spaces in filenames)
find docs/ -name '*2026-06-03*' -type f -print0 | xargs -0 nvim
Grep → Open results in nvim
# Find files containing a term, open all in nvim
grep -Rl --include='*.adoc' 'cert.*auth' . | xargs nvim

# With line numbers
grep -Rn --include='*.adoc' 'Client Authentication' . | head -20
Content Inspection (without opening)
# Structure map — all section headers
grep -n '^=\+ ' file.adoc

# Dependency map — all includes
grep -n 'include::' file.adoc

# Uniqueness check (before sed)
grep -c 'pattern' file.adoc

# Context around a match
grep -n -B3 -A3 'pattern' file.adoc

# View specific line range
awk 'NR>=42 && NR<=92' file.adoc

# Count matches per file across repo
grep -Rn --include='*.adoc' 'cert' . \
  | awk -F: '{count[$1]++} END {for (f in count) print count[f], f}' \
  | sort -nr
Process Substitution (compare without temp files)
# Compare two command outputs
diff <(command-a) <(command-b)

# Compare two PDFs
diff -u \
  <(pdftotext "file-a.pdf" - | grep -Ei 'PATTERN') \
  <(pdftotext "file-b.pdf" - | grep -Ei 'PATTERN')

# Compare two API responses
diff <(curl -s url-a | jq '.') <(curl -s url-b | jq '.')
d000 / d001 Shortcuts
d000 LECTURA-PRIMEROS-PASOS              # fuzzy open
d000 build p1-cap-038-notas pdf --theme dark  # build
d001 open okta-to-entra                  # decrypt
d001 build ise-cert-renewal-procedure pdf --theme navy
d001 close okta-to-entra                 # encrypt + stage
Pipeline: Find → Filter → Extract → Act
# General pattern
find <where> -name '<what>' -type f |
  xargs grep -Il '<content>' |
  xargs nvim

# Concrete: ISE cert files → open in nvim
find . -name '*.adoc' -type f |
  xargs grep -Il 'cert.*ISE\|ISE.*cert' |
  xargs nvim

Git — Undo a Commit Without Losing Work

Existing codex: partial$codex/git/git-quick-reference.adoc (§ Undoing Things, lines 145–163)

This partial adds the verify pattern and explains what each level preserves.

Three levels of undo
Command Files become Use when

git reset --soft HEAD~1

Staged (green in git status)

Wrong commit message, want to re-commit differently

git reset HEAD~1

Modified but unstaged (red in git status)

Want to rearrange what gets committed

git reset HEAD~1 + git restore --staged .

Modified + new files return to untracked

Want to go back to before git add entirely

git reset --hard HEAD~1 destroys changes from disk. Never use unless you mean it.
Verify-before / change / verify-after
Undo last commit, keep files unstaged (most common)
# Before — confirm what the last commit contains
git log --oneline -3
git show --stat HEAD

# Change — undo the commit
git reset HEAD~1

# After — files are back to modified/untracked
git status
Undo last N commits
# ~1 = one commit, ~2 = two commits, ~3 = three, etc.
git reset HEAD~2
Find it later — reflog keeps everything for 90 days
# The commit is NOT gone — git reflog shows every HEAD position
git reflog | head -5

# Recover an undone commit by its hash
git cherry-pick <hash>
How to find this partial
# By keyword — from anywhere in the repo
grep -rl 'undo.*commit\|reset.*HEAD' docs/modules/ROOT/partials/ --include='*.adoc'

# By filename
find docs/modules/ROOT/partials/worklog -name '*git-undo*'

# In the codex (existing terse version)
grep -n 'reset.*HEAD' docs/modules/ROOT/partials/codex/git/git-quick-reference.adoc

JSONL + jq — Practical Workflows

Existing codex references:

  • partial$codex/json-yaml/jq/files.adoc — file ops, validate, merge, JSONL basics

  • partial$codex/json-yaml/jq/advanced.adoc — --arg, regex, streaming, recursive descent

  • data/d000/…​/quijote-study/partials/jsonl-search-methodology.adoc — Claude Code session search (7-step)

This partial adds the daily-use patterns for work and personal contexts.

What is JSONL?

One JSON object per line. No wrapping array. Every line is independently parseable.

{"id":1,"name":"alpha","status":"active"}
{"id":2,"name":"beta","status":"inactive"}
{"id":3,"name":"gamma","status":"active"}

Why it matters: log files, API streams, Claude Code sessions, Monad pipeline output, Sentinel query results — all use JSONL. It’s the lingua franca between JSON tools and line-oriented Unix tools.

Core pattern: grep prefilter → jq refine
# grep is fast on raw text — prefilter BEFORE jq parses
grep 'search-term' data.jsonl | jq '{name: .name, status: .status}'

grep scans at disk speed. jq parses JSON. Combining them: grep narrows to relevant lines, jq extracts structure. Never run jq on a 500MB file without grep first.

Extract fields from JSONL
Select specific fields from every line
jq -r '{name: .name, ip: .ip}' devices.jsonl
Tab-separated output for terminal viewing
jq -r '[.name, .status, .ip] | @tsv' devices.jsonl
CSV output
jq -r '[.name, .status, .ip] | @csv' devices.jsonl
Filter JSONL
Select lines matching a condition
jq 'select(.status == "active")' devices.jsonl
Multiple conditions
jq 'select(.status == "active" and .vlan == 10)' devices.jsonl
Regex filter on a field
jq 'select(.name | test("^ise-"))' devices.jsonl
Negate — everything that does NOT match
jq 'select(.status != "inactive")' devices.jsonl
Aggregate JSONL
Count lines
jq -s 'length' data.jsonl
Count by group
jq -s 'group_by(.status) | map({status: .[0].status, count: length})' data.jsonl
Unique values of a field
jq -r '.status' data.jsonl | sort -u
Sum a numeric field
jq -s 'map(.bytes) | add' traffic.jsonl
Transform between formats
JSON array → JSONL
jq -c '.[]' array.json > output.jsonl
JSONL → JSON array
jq -s '.' input.jsonl > array.json
JSONL → readable table with awk
jq -r '[.name, .status] | @tsv' data.jsonl | awk -F'\t' '{printf "%-20s %s\n", $1, $2}'
Claude Code sessions — quick commands
# Where are my sessions?
ls ~/.claude/projects/-home-evanusmodestus-atelier--bibliotheca-domus-captures/*.jsonl | wc -l

# Find sessions mentioning a topic
grep -rli 'atributos\|protocolo' \
  ~/.claude/projects/-home-evanusmodestus-atelier--bibliotheca-domus-captures/ \
  --include='*.jsonl' | grep -v '/subagents/'

# Extract my messages from a session
grep '"role":"user"' <session>.jsonl | jq -r '
  .message.content |
  if type == "array" then
    map(select(.type == "text") | .text) | join(" ")
  elif type == "string" then .
  else empty end
' 2>/dev/null | awk 'NF && length > 10' | head -20

Full methodology: d000 quijote-studypartials/jsonl-search-methodology.adoc

Work contexts — ISE, Monad, Sentinel
ISE ERS API response — extract endpoint details
curl -sk https://ise-01/ers/config/endpoint \
  -H 'Accept: application/json' -u admin:pass | \
  jq -r '.SearchResult.resources[] | [.name, .id] | @tsv'
Monad pipeline output — filter by source
jq 'select(.source == "ise")' pipeline-output.jsonl | jq -r '.mac'
Sentinel/KQL JSON results — flatten nested
jq -r '.[] | [.TimeGenerated, .Computer, .EventID] | @tsv' sentinel-results.json
How to find this partial later
grep -rl 'jsonl.*jq\|jq.*jsonl\|JSONL' docs/modules/ROOT/partials/ --include='*.adoc'

Education — Evening Sessions

Cicerón — De Inventione

Started: 2026-06-03 (late night / early morning)
Guide: d000 LECTURA-PRIMEROS-PASOS
Key passage: prólogo, líneas 42–92 — elocuencia + sabiduría
Connection: The Five Canons applied to ESA investigation above — inventio through pronuntiatio as technical analysis framework.

Don Quijote — Lectura del día

Capítulo: XXXVIII (tercera lectura) / XXXIX (inicio del Cautivo)
Build: d000 build p1-cap-038-notas html --variant catppuccin
Custom roles: .cervantes, .retorica, .testimonio, .teologia, .gramatica, .ironia, .pregunta

Lo que leí hoy

Escribe en español.

Vocabulario nuevo
Palabra Definición Ejemplo en contexto

palabra

definición

cita del texto

Conexiones con Cicerón

De Inventione, prólogo (líneas 42–92) — ¿qué conecta con lo que leíste hoy?

Notas para SIELE/DELE
  • Registro formal observado:

  • Estructura sintáctica compleja:

AsciiDoc Inline Emphasis — Marking Words for Study

Reference for highlighting, annotating, and visually distinguishing words and phrases in reading notes.

Core emphasis — single characters
Syntax Renders as Use for

*bold*

bold

Key terms, vocabulary words, first occurrence of a concept

_italic_

italic

Foreign words, titles, Spanish phrases in English prose

*_bold italic_*

bold italic

Maximum weight — thesis statements, critical terms

`monospace`

monospace

Commands, code, literal strings, grammatical forms like -are/-iere

Highlight and mark — visual emphasis
Syntax Renders as Use for

#highlighted#`

highlighted

Yellow background mark — words to study, vocabulary to memorize

##double hash for custom roles##

Pass-through for role application

Required when combining roles with marks (see custom roles below)

[.underline]#underlined#

underlined

Structural emphasis — topic sentences, key phrases in long passages

[.line-through]#struck#

struck

Corrections, superseded translations, wrong-then-right pattern

Size modifiers
Syntax Renders as Use for

[.big]##larger text##

larger text

Section labels, visual hierarchy without headings

[.small]##smaller text##

smaller text

Meta-commentary, grammar labels, register notes under annotations

^superscript^

superscript

Footnote markers, edition numbers, century indicators (XVIIe)

~subscript~

subscript

Chemical formulas, phonetic notation

Combining roles — the power syntax

Single requires unique text. Double # allows role application to any span.

Bold + highlighted (study word with emphasis)
The word *#garbeare#* is a subjuntivo futuro — extinct in modern Spanish.

Renders: The word garbeare is a subjuntivo futuro — extinct in modern Spanish.

Underline + italic (foreign term requiring attention)
[.underline]##_effictio_## is the rhetorical term for a head-to-toe physical description.

Renders: effictio is the rhetorical term for a head-to-toe physical description.

Small text for meta-commentary under annotations
está *atenido* a la miseria de su paga:::
_Dependiente de._ Su vida entera cuelga de un salario que no controla. +
[.small]##Dativo de interés · B2 · «atenerse a» = depender de##
Strikethrough → correction pattern (wrong then right)
[.line-through]#«puesto que» = because# → «puesto que» = *although* (Siglo de Oro concessive)

Renders: «puesto que» = because → «puesto que» = although (Siglo de Oro concessive)

Custom literary roles (from domus-asciidoc-build)

These require the Catppuccin variant CSS (--variant catppuccin or --theme don-quijote).

Role Color / Icon Purpose

[.cervantes]

Mauve / pencil

Autobiographical voice — author behind character

[.retorica]

Blue / balance scale

Rhetorical figures, dispositio, persuasion

[.testimonio]

Teal / shield

Personal experience, military testimony

[.teologia]

Gold / book

Moral/theological reading, sacred layer

[.gramatica]

Green / graduation cap

Siglo de Oro syntax, archaisms, extinct forms

[.ironia]

Peach / exclamation

Cervantine humor, double meaning

[.pregunta]

Pink / question circle

Open questions, unresolved threads

Usage — sidebar block with role
[.gramatica]
.Subjuntivo futuro — forma extinta
****
«Garbeare» es subjuntivo futuro de «garbear». Hoy diríamos «lo que pueda robar».
****
Practical patterns for Quijote annotations
Vocabulary word on first encounter
un *#coleto acuchillado#* le sirve de gala
Grammar label with small meta
*garbeare*::: _robar, saquear_ +
[.small]##subjuntivo futuro · forma extinta · C2##
Rhetorical device name with underline
[.underline]##Epizeuxis## — «sí, sí» — repetición inmediata como acto performativo.
CEFR level as superscript after vocabulary
*atenido a* — dependiente de ^B2^
*garbeare* — futuro de subjuntivo de _garbear_ ^C2^
*coleto acuchillado* — chaleco de cuero con cortes ^C1^
Cross-reference to full emphasis table
See xref:education/programming/rust/asciidoc-notes-syntax.adoc[AsciiDoc Notes Syntax] for the complete formatting reference.
Protocolo de Marcas — Alumno ↔ Profesor
Marca Nombre Contrato

{mark-d}

Dubium

No entiendo → definición + nivel

{mark-q}

Quaestio

Quiero el fondo → definición + etimología + por qué

{mark-p} 💡

Placet

Me gusta / me llama la atención → técnica + efecto

{mark-dl}

Delectat

Me deleita / quiero la arquitectura → multicapa

{mark-m} 🌟

Mirabile

Me maravilla / me detiene → todo, sin límite

Sintaxis — al final de cada sección
.Mis marcas — §N
[horizontal]
palabra o frase:: {mark-d}
otra palabra:: {mark-q}
pasaje completo:: {mark-m}
Reglas
  • La marca es el techo — nunca recibe etimología

  • Sin vergüenza — en una palabra «fácil» es legítimo

  • Escalar — si despierta curiosidad, remarcar como o 💡

  • Frases completas son válidas — no solo palabras sueltas

Quijote XXXVII — Texto Anotado + Atributos System

Created: p1-cap-037-texto-anotado.adoc — full chapter with custom study marks across all 29 sections.

Atributos file: atributos-quijote.adoc — single source of truth for the entire Quijote study. 11 categories, included with one line in any chapter file.

What was built:

  1. p1-cap-037-texto-anotado.adoc — full chapter text with ~90 vocabulary items (bold highlight + CEFR), ~20 archaic forms (bold italic), ~15 grammar annotations ( monospace ), ~20 rhetorical structures (underline)

  2. atributos-quijote.adoc — reusable attributes file: protocol marks, CEFR levels, grammar labels, rhetorical figures, dispositio, characters, biblical references, Arabic etymologies, chapter navigation

  3. protocolo-marcas.adoc — Antora partial + d000 standalone: the 5-level study annotation system (Dubium → Quaestio → Placet → Delectat → Mirabile)

  4. protocolo-lectura.adoc — full protocol contract: what each mark means, how to use it, how the professor responds

Attribute system — how it works:

AsciiDoc attributes are key-value pairs defined once and substituted everywhere at build time.

// In atributos-quijote.adoc (definition):
:mark-d: ❓
:subj-fut: [.small]##subjuntivo futuro · forma extinta##
:c2: ^C2^
:ar-burgi: [.small]##del árabe burġī — bota alta##

// In any texto-anotado (usage):
pagalle:: {mark-d}
`quisiere` {subj-fut}
*#borceguíes#* {c2} {ar-burgi}

The same mechanism as {ise-01-ip}10.50.1.20 in infrastructure docs. Attributes don’t care what the value is — text, emoji, IP address, rhetorical label.

Live workflow:

Terminal 1

d000 build p1-cap-037-texto-anotado html --variant catppuccin --watch

Terminal 2

nvim editing the .adoc file

Browser

…​output/p1-cap-037-texto-anotado.html — refresh after :w

Watch mode fix: inotifywait -e modify broke after first save because nvim writes via temp-file-then-rename (inode changes). Fixed to watch the directory for close_write,moved_to events. Committed to domus-asciidoc-build.

First marks test — §2 (prueba):

Mis marcas — §2
pagalle

❓ ❓

jubilaba

❔ ❔

era el afligido, el desventurado y el triste

🌟 🌟

All attributes resolved. Marks render correctly in browser.

Violin

Evening session: Gavotte — J. Becker. 1 hour.
Scales, left hand technique, bowings.

Don Quijote — Lectura

Evening session: 30 min so far — re-reading Caps. XXXVII + XXXVIII.
Continuing through both chapters tonight.

Discovery — Wayland Screenshots

grim for full screen, grim -g "$(slurp)" for region select. Install: sudo pacman -S grim slurp.

Nutrition

~2100 calories.


Work (CHLA)

CHARGE TIME IN PEOPLESOFT - CRITICAL. Do this NOW before anything else.

Critical (P0)

Project Description Owner Status Due Blocker

Linux Research (Xianming Ding)

EAP-TLS for Linux workstations, dACL, UFW

Evan

BEHIND (72 days overdue)

02-24

Certificate "password required" - nmcli fix documented

iPSK Manager

Pre-shared key automation

Ben Castillo

BEHIND

 — 

DB replication issues

MSCHAPv2 Migration

Legacy auth deprecation — 6,227 devices, 5 waves. 6 batch SQL queries + 3-API endpoint profile script added (05-11). Report due.

Evan

25% — Report due, batch queries ready

05-30

Report to turn in

Research Segmentation

All endpoints to Untrusted VLAN

Evan

BLOCKED

 — 

CISO decision pending

Disaster Recovery

ISE DR scoping — dot1x closed mode = total blackout

Evan

Scoping

 — 

 — 

Mandiant Remediation

Copy 4/16 findings, Guest ACL lab, Q2 assessment

Evan

Active

 — 

 — 

SIEM QRadar → Sentinel

Full SIEM platform transition. Monad console error resolved 05-12. Secrets configured. Blocked on DCR creation (Rule ID + Stream Name). Azure private network policy unresolved.

Evan

Active — blocked on DCR

Q2 2026

Victor/Mauricio: create DCR, resolve Azure network policy

Abnormal Security

AI email platform — ESA cutover. CR assigned, CAB May 12 15:00. Implementation May 14 10:00.

Evan

Active — CAB today 15:00

05-14

Pre-CAB checklist: confirm Tyler, Jason, Sarah

High Priority (P1)

Project Description Owner Status Target

ISE 3.4 Migration

Upgrade from 3.2p9

Evan

Blocked — maintenance window needed

Q2 2026

Switch Upgrades

IOS-XE fleet update (C9300, 3560CX)

Evan

Pending

Q2 2026

Spikewell BYOD VPN

dACL SQL, AD group integration

Evan

Active

 — 

Strongline Gateway

MAC capture, Identity Group setup — 37 days aging

Evan

Active — David Rukiza assigned

 — 

Abnormal Security

AI email security platform research, ESA cutover timeline

Evan

Newly assigned

 — 

DMZ Migration

External services audit behind NetScaler

Evan

Audit phase

 — 

Firewall Audit (murus-portae)

EtherChannel query, prefilter, policy assignments

Evan

Scoping — ASA API creds needed

 — 

iPSK Manager HA

Server 2 config, TLS, SQL security audit

Evan

In progress

 — 

Sentinel KQL

Build proficiency, distinguish from team

Evan

Onboarding

 — 

VNC Blocking

Block and eliminate VNC protocol enterprise-wide

Evan

Active — Phase 0 (Discovery)

Mid-June 2026

Strategic (P2)

Project Description Owner Status

HHS Regulatory Compliance

New HHS security policies implementation

TBD

NOT STARTED

InfoSec Reporting Dashboard

PowerBI metrics for executives

TBD

NOT STARTED

EDR Migration (AMP → Defender)

Endpoint protection consolidation

TBD

NOT STARTED

Azure Legacy Migration

Modern landing zone

Team

In Progress

ChromeOS EAP-TLS

SCEP + Victor, Paul testing

Victor

In Progress

P0 — Critical / Blocking

Security & Compliance

  • ISE 3.2 Patch 10 upgrade — CVE-2026-20147 CVSS 9.9 / CVE-2026-20148. Propose maintenance window once patch confirmed on software.cisco.com.

  • ISE Advisory sa-ise-rce-traversal-8bYndVrZ — check Patch 10 availability

  • Mandiant Remediation — findings status tracked. Working session prep + defensive posture documented (comms-2026-04-24). Copy 4/16 updates into Excel at work. Guest ACL lockdown (WIR-M-01) pending lab validation. appendix-todos updated with MSCHAPv2 milestones.

  • Guest ACL update — guest redirect ACL work needed. Lab validate GUEST_CWA_REDIRECT_MAX_SECURITY in d000, then joint CR with NE. On today’s task list.

  • Disaster Recovery & Downtime Procedures — ISE top priority (dot1x closed mode = SPOF for network access)

    • ISE DR: Document failover sequence — PAN, MnT, PSN priority order

    • ISE DR: RADIUS dead-server detection on WLCs/switches — critical-auth VLAN fallback

    • ISE DR: Backup/restore procedures — scheduled config backups, tested restores

    • FTD/FMC DR: FMC loss = no policy management

    • Network DR: Core/distribution switch failure, STP reconvergence, HSRP failover

    • Document RTO/RPO per system

SIEM Migration (QRadar → Sentinel)

  • SIEM QRadar → Sentinel Migration — LEAD ROLE. 4 collection iterations (Apr 16, 17, 17-streamlined, 20-streamlined). Python chart pipeline built (qradar-charts.py). Migration XLSX generated. Verification pending. Comms sent Apr 23.

    • d001 artifacts: 8 JSON exports, 2 CSV inventories, migration XLSX, top5 source SVG/PNG, verification doc

    • Dependency: Monad pipeline for log source transition

    • Dependency: Sentinel KQL proficiency for query migration

  • Monad Pipeline Evaluation (origin: 2026-03-11) — lead role. Console error RESOLVED 05-12 — secrets configured in CHLA production tenant. Blocked on DCR creation (Rule ID + Stream Name). Azure private network policy unresolved. 10am call today 05-12.

  • Sentinel KQL — build proficiency, distinguish from team. Azure portal access acquired.

  • QRadar log source report — run AQL queries, fetch JSON, generate Python Excel

Active Deployments & Migrations

  • MSCHAPv2 Migration — Report due. 6-sheet Standard Report ready (Sheet 6: policy match by protocol added 05-14 for removal planning + anonymous identity validation on cert profiles). Migration window 5/4 – 5/30. 6,227 MSCHAPv2 devices, 14,249 EAP-TLS/TEAP (70% migrated). Focus: run Standard Report, turn in spreadsheet.

  • MSCHAPv2 weekly cadence — recurring Wednesday call established (first 04-22). Completed 2026-04-22.

  • MSCHAPv2 ownership matrix — sent in scoping email 4/24 with manager callouts (@Albert, @John). Completed 2026-04-24.

  • TCP Clocks deployment — new device added via ERS POST and confirmed (04-24). 7+ clocks validated. v2 query file with partials architecture. Revalidate full set — confirm no flapping.

  • SRT Research VLAN — confirm roles with Tony Sun: Tony implementor, Evan tester. CAB approved 04-21.

  • Downtime Computers enforcement — draft ISE AuthZ rule: medigate_724 + Wireless = DenyAccess. Separate CR. d001: DC queries, audit CSVs (v1-v3), wireless violations report delivered 04-21.

  • Enterprise Linux 802.1X — standardize Shahab/Ding deployment (CISO priority). Overdue since 02-24. Blocked by nmcli cert fix.

  • Abnormal Security — CR-2026-05-07-abnormal-read-write. CAB 05-12 approved, implementation 05-14. Jason Landeros implements, Evan presents. 06-01 update: Review Jihad’s policy mapping XLSX + Tyler’s Policy and Rules Migration doc before next call. Plan email migration expansion beyond security group to full environment — priority to move off ESA. Exchange rule considerations: external sender disclaimer (sender not company, outside org, not internal IP → prepend disclaimer).

    • Team: Cox/William, Landeros/Jason, Rosado/Evan, Naranjo/Mauricio, Sandoval/Carlos

Tube System Upgrade (NEW — 06-01)

  • Tube System Upgrade — iTrack 3528165. 15x 10" TS stations need MAC addresses added to ISE identity group IoT_Onboard. MACs received from vendor (C8:1A:FE:20:xx:xx series). Station list spans ICU (CTICU, PICU, BMT, NICU, NICCU), ED, Surgery, Trauma, Pharmacy. Vendor contact: John Genest. Rationale: manufacturer no longer supports current system; failure risks delayed/missed patient care.

BMS Device Inventory (NEW — 04-24)

  • BMS Device Inventory — 72 devices discovered across 37 switches (04-24). Profile-driven architecture (Claroty/Medigate). 16 queries built. Phase 0 complete. Next: cross-reference with Visio diagrams, classify by function, begin D2 diagrams. Cleanup: delete 4 orphaned test groups, migrate 4 retire-dACL devices, investigate 3 null-profile devices.

VNC Blocking (NEW — 05-11)

  • VNC Blocking — block and eliminate VNC enterprise-wide. Due mid-June 2026. Phase 0: discovery. January AQL query baseline to incorporate. Cross-reference BMS inventory for VNC-capable devices.

Investigations & Audits

  • Murus Portae (WAF) — Phase 0 discovery in progress. FMC cert expired. d001: DMZ NetScaler WAF investigation, zone map, architecture D2 diagrams (v1+v2 SVGs), FMC REST API reference guide, ops script. FMC API returning zero ACP rules — under investigation.

  • Firewall audit — FMC discovery inventory done (d001: fmc-discovery-2026-04-16). EtherChannel query, prefilter, policy assignments pending.

  • IoT Dr. Kim devices — RECURRING. All 4 MACs validated in IoT_iPSK_VLAN1620_Misc (04-24). v2 validation queries built with 7 deep analysis queries (group flapping, credential leakage, profile drift, NAS tracking, remediation timeline, deny audit, OUI scan). Revalidate — confirm no flapping since 04-24.

  • IoT device validation queries — v2 created with partials architecture, 16 queries across ERS/MnT/DataConnect/FMC. Completed 2026-04-24.

Stale Blockers (carried via carryover tracker)

  • k3s NAT verification — rule 170, 10.42.0.0/16 pod network (origin: 2026-03-09). 59 days. Blocks Wazuh indexer recovery → blocks SIEM visibility. Weekend task?

  • Strongline Gateway VLAN fix — 8 devices wrong identity group (origin: 2026-03-16). 52 days. David Rukiza assigned — follow up on status.

Administrative

  • PeopleSoft — track time for current week

  • iTrack tickets — close open tickets

  • KQL library — build initial queries in codex + d001

  • Linux Research project — finalize and review

  • Tax filing 2025 (MFJ) — see encrypted case file in data/d000/personal/ for details and action items

P1 — Important

  • MSCHAPv2 action-item tracker — owner/status/next-steps per workstream

  • ISE admin MFA enforcement — recommendation tied to advisory (interim control pending Patch 10)

  • DMZ Migration — external services audit behind NetScaler. Linked to Murus Portae investigation.

  • Vocera/Wyse iTrack RCA — complete root cause report

  • GCC ISE Support — 3/4 nodes restored, PSN-04 deferred

  • Wazuh indexer recovery — blocked by k3s NAT (origin: 2026-03-09)

  • Vocera EAP-TLS Supplicant Fix (origin: 2026-03-12)

  • iPSK Manager HA — blocked by DB replication (Ben Castillo)

  • ISE 3.4 Migration — depends on Patch 10 completion first

  • Git history scrub — murus-portae-output.md + ise-analytics CSVs

  • Encrypt prep-cmds-2026-04-15.adoc — plaintext committed to git

  • ISE MnT Messaging Service — enable UDP syslog delivery (maintenance window needed)

Infrastructure (Personal)

  • Borg backups — test and validate on ALL systems (Razer, P16g, vault-01, bind-01, kvm-01, kvm-02)

  • Borg — verify backup script paths updated from dotfiles-optimus to dots-quantum

  • Borg — create initial archive for ThinkPad P16g if none exists

  • Libvirt VLAN hook debug on both KVMs

  • Te1/0/2 cable replacement and re-test

  • Vault Raft cluster — verify vault-01 rejoined

  • Fix EAP-TLS keyring/secrets issue on Razer workstation

Completed (confirmed — do not delete, archive only)

  • CR-2026-04-15 SRT Research VLAN — submitted to iTrack. Completed 2026-04-15.

  • CAB presentation 4/21 — SRT Research VLAN 233 → CHLA-Research. APPROVED. Completed 2026-04-21.

  • Downtime Computers wireless audit — 45 computers, 16 violating, v3 report delivered. Completed 2026-04-21.

  • Git identity fix — dots-quantum/git/.gitconfig email corrected. Completed 2026-04-21.

  • MSCHAPv2 10:30 meeting — next steps + ACL coordination. Completed 2026-04-17.

Service Requests (SR)

SR# Request Requestor Opened Status

3508542

Zoll cards connection issue

STALE — verify in iTrack

3508524

Disable dot1x on (2) network ports - 5th floor 3250 Wilshire (PXE-boot imaging issues)

STALE — verify in iTrack (issues persisted after disable)

3528165

Tube System Upgrade — 15 stations, MAC addresses for ISE IoT_Onboard identity group

Genest, John (vendor contact)

2026-06-01

NEW — MACs received, need ISE onboarding

Incidents (INC)

INC# Priority Description Opened SLA Status

1911859

Strongline Gateways in Miscellaneous Subnet

STALE — verify in iTrack (related to carryover P0)

Change Requests - Emergency (ECAB)

CR# Description Opened Scheduled Status

No emergency changes

Change Requests - Normal

CR# Description Opened Scheduled Status

No normal changes

Change Requests - Scheduled/Standard

CR# Description Opened Window Status

No scheduled changes

Change Requests - Root Cause / Post-Incident

CR# Description Related INC Opened Status

100451

Vocera Phones and Wyse devices went off network

STALE — verify in iTrack


Session Accomplishments (Claude Code)

Day-specific accomplishments here.


Personal

In Progress

Project Description Status Notes

k3s Platform

Production k3s cluster on kvm-01

Active

Prometheus, Grafana, Wazuh deployed

Wazuh Archives

Enable archives indexing in Filebeat

Active

PVC fix pending

kvm-02 Hardware

Supermicro B deployment

Active

Hardware ready, RAM upgrade done

Planned

Project Description Target Blocked By

Vault HA (3-node)

vault-02, vault-03 on kvm-02

Q2 2026 (slipped from Q1)

kvm-02 deployment

k3s HA (3-node)

Control plane HA

Q2 2026 (slipped from Q1)

kvm-02 deployment

ArgoCD GitOps

k3s GitOps deployment

After k3s stable

 — 

MinIO S3

Object storage for k3s

After ArgoCD

 — 

Domus Inventory

Personal asset management (YAML + CLI + AsciiDoc)

Q2 2026

Schema approved

Active — Infrastructure

Task Details Priority Status Due

Wazuh agent deployment

Deploy agents to all infrastructure hosts

P2

Pending

After archives fix

k3s Platform

Production k3s cluster on kvm-01

P1

In Progress

 — 

Wazuh Archives

Enable archives indexing in Filebeat, PVC fix

P1

In Progress

 — 

kvm-02 Hardware

Supermicro B deployment, RAM upgrade done

P1

In Progress

 — 


Active — Security & Encryption

Task Details Priority Status Due

Configure 4th YubiKey

SSH FIDO2 keys

P1

TODO

 — 

Cold storage M-DISC backup

age-encrypted archives

P1

TODO

After YubiKey setup


Active — Development & Tools

Task Details Priority Status Due

netapi Commercialization

Go CLI rewrite with Cobra-style argument discovery, package for distribution

P0

Active

 — 

Ollama API Service

FastAPI (17 endpoints), productize — config audit, doc tools, runbook gen

P0

Active

 — 

Shell functions (fe, fec, fef)

File hunting helpers

P3

TODO

 — 


Active — Documentation

Task Details Priority Status Due

D2 Catppuccin Mocha styling

domus-* spoke repos (177 files total)

P3

In Progress

 — 


Active — Financial

Task Details Priority Status Due

Amazon order history import

Download CSV from Privacy Central → parse with awk → populate subscriptions tracker

P1

Waiting

Pending Amazon data export (requested 2026-04-04)


Active — Education

Task Details Priority Status Due

No active education tasks — see education trackers


Active — Personal & Life Admin

Task Details Priority Status Due

ThinkPad T16g Setup

Arch install, stow dotfiles, Ollama stack, netapi dev env

P0

Pending

 — 

P50 Arch to Ubuntu migration

CR-2026-03-12

P2

In Progress

 — 

X1 Carbon Ubuntu installs

2 laptops, LUKS encryption

P2

In Progress

 — 

P50 Steam Test

Test Flatpak Steam + apt cleanup of broken i386 packages

P3

Pending

 — 

Documentation Sites

Notes

Day-specific personal notes here.


Education

Claude Code Mastery

Resource Details Progress Status

Claude Code Full Course (4 hrs)

Nick Saraev - YouTube comprehensive course

26:49 / 4:00:00

IN PROGRESS

Claude Code Certification

Anthropic official certification (newly released)

Not started

GOAL

Skills Mastery (Critical)

Certification Deadlines

  • CISSP - July 12, 2026 (10-week plan active — Week 1)

  • RHCSA 9 - Q3 2026 (after CISSP)

  • LPIC-1 - Renewal required (blocks LPIC-2)

Spanish C1 Certification Goals

Certification Provider Target Status Strategy

SIELE C1

Instituto Cervantes / UNAM / Salamanca

Q2 2026

ACTIVE

Computer-based, faster results - take FIRST

DELE C1

Instituto Cervantes

Q3/Q4 2026

PLANNED

After SIELE success, harder exam

DELE C2

Instituto Cervantes

2027

FUTURE

Mastery level - requires extensive immersion

SIELE is computer-adaptive, results in 3 weeks. DELE is paper-based, results in 3-4 months. Do SIELE first to validate readiness.

Don Quijote Writing Practice - DELE C1/C2 Initiative

Method:

  1. Read chapter in original Spanish

  2. Write personal analysis/understanding en espanol

  3. AI review for grammar, vocabulary, register

  4. Build comprehensive understanding of literary elements

Today’s Study

  • Focus: CISSP (41 days to July 12 exam — schedule exam today 06-01), MSCHAPv2 migration wrap-up

  • Secondary: RHCSA curriculum, Spanish SIELE C1

  • CISSP — Security & Risk Management (continuing). Schedule exam this afternoon.

  • RHCSA — continue curriculum phase

  • Spanish — Don Quijote reading + analysis (DTLA study day)

  • MSCHAPv2 — migration window closed 05-30, review final report

Regex Training (CRITICAL)

  • Status: 52 days carried over (since 2026-03-16)

  • Priority: After PeopleSoft, before Quijote

  • Session: Character classes, word boundaries


Infrastructure

Documentation Sites

Site URL Status Actions Needed

Domus Digitalis

docs.domusdigitalis.dev

Active

Validate, harden, improve

Architectus

docs.architectus.dev

Active

Public portfolio site - maintain

HA Deployment Status

System Description Status Notes

VyOS HA

vyos-01 (kvm-01) + vyos-02 (kvm-02) with VRRP VIP

✅ COMPLETE

2026-03-07 - pfSense decommissioned

BIND DNS HA

bind-01 (kvm-01) + bind-02 (kvm-02) with AXFR

✅ COMPLETE

Zone transfer operational

Vault HA

Raft cluster (vault-01/02/03)

✅ COMPLETE

Integrated with PKI

Keycloak Rebuild

keycloak-01 corrupted, rebuild from scratch

🔄 NEXT

Priority P3 - SSO broken

FreeIPA HA

ipa-02 replica planned

📋 PLANNED

Linux auth redundancy

AD DC HA

home-dc02 replication

📋 PLANNED

Windows auth redundancy

iPSK Manager HA

ipsk-mgr-02 with MySQL replication

📋 PLANNED

PSK portal redundancy

ISE HA

PAN HA (ise-01 reconfigure)

⏳ DEFERRED

Wait until ise-02 stable

ISE 3.5 Migration

Upgrade path: 3.2p9 → 3.4 (P1) → 3.5 (target)

📋 PLANNED

After 3.4 Migration completes (Q2 2026)

Single Points of Failure (CRITICAL)

These systems have NO redundancy - outage impacts production.
System Impact if Down Mitigation

ISE (ise-02)

All 802.1X stops - wired and wireless auth fails

ise-01 reconfiguration deferred until ise-02 stable

Keycloak (keycloak-01)

SAML/OIDC SSO broken (ISE admin, Grafana, etc.)

NEXT PRIORITY - Rebuild runbook

FreeIPA (ipa-01)

Linux auth, sudo rules, HBAC fails

ipa-02 replica planned

AD DC (home-dc01)

Windows auth, Kerberos, GPO fails

home-dc02 replica planned

iPSK Manager

Self-service PSK portal unavailable

ipsk-mgr-02 with MySQL replication planned

Validation Tasks

Task Details Status

docs.domusdigitalis.dev validation

Test all cross-references, search, rendering

TODO

docs.domusdigitalis.dev hardening

HTTPS, CSP headers, security review

TODO

docs.architectus.dev validation

Public site content review

TODO

Hub-spoke sync verification

All components building correctly

Ongoing


Quick Commands

Git & GitHub CLI

create GitHub repo from existing local repo
gh repo create <name> --private --source . --remote origin --push
clone a forked repo into a specific directory
gh repo clone EvanusModestus/PowerShell ~/atelier/_projects/work/PowerShell
gh repo clone defaults to SSH. If key is passphrase-protected, load agent first: eval "$(ssh-agent -s)" && ssh-add ~/.ssh/id_ed25519_github
cross-repo commit search — all domus repos on a specific date
for repo in ~/atelier/_bibliotheca/domus-*/ ~/atelier/_projects/personal/domus-*/; do
  [ -d "$repo/.git" ] || continue
  name=$(basename "$repo")
  git -C "$repo" log --since="2026-04-06" --until="2026-04-07" --format="%h %aI %s" 2>/dev/null |
    awk -v r="$name" '{print r, $0}'
done
commit history touching only today’s modified files
git log --oneline -- $(find . -name "*.adoc" -type f -newermt "$(date +%F)")
unstage a file without losing changes
git restore --staged data/d001/api/ise-dataconnect/output/output-2026-04-24

Safe — removes from staging area only. Working tree is untouched. Use when you accidentally git add a plaintext or output file.

gh CLI — repo discovery and filtering

list repos by name pattern (domus/antora ecosystem)
gh repo list --limit 100 --json name,description \
  | jq -r '.[] | select(.name | test("domus|antora|asciidoc"; "i")) | "\(.name)\t\(.description)"'
top 20 most recently updated repos
gh repo list --limit 100 --json name,description,updatedAt \
  | jq -r 'sort_by(.updatedAt) | reverse | .[:20] | .[] | "\(.updatedAt[:10])\t\(.name)\t\(.description)"'
top 10 repos by disk usage
gh repo list --limit 100 --json name,diskUsage \
  | jq -r '.[] | "\(.diskUsage)\t\(.name)"' | sort -rn | head -10
clone a repo that’s not local yet
gh repo clone EvanusModestus/<repo-name> ~/atelier/_bibliotheca/<repo-name>

find & grep

files modified since midnight today (precise — not "last 24 hours")
find . -name "*.adoc" -type f -newermt "$(date +%F)" | sort
-mtime 0 means "last 24 hours", not "today". -newermt "$(date +%F)" compares against midnight — exact.
case-insensitive file search
find . -iname "*mschap*" -type f | sort
multiple name patterns with -o
find . -type f \( -iname "*ise*" -o -iname "*mschap*" \) | sort
same thing, single regex — fewer parens, extensible
find . -type f -iregex '.*\(ise\|mschap\).*'
exclude directories
find . -type f -iname "*meeting*" \
  -not -path "*/node_modules/*" \
  -not -path "*/.git/*" \
  -not -path "*/build/*"
recent drafts by modification time (newest first)
find .drafts -type f -printf '%T@ %Tc %p\n' | sort -rn | awk '{$1="";print}' | head -3
grep — know what you’re counting
grep -rl "pattern" . --include="*.adoc"         # file count (which files)
grep -rn "pattern" . --include="*.adoc"         # line matches (every occurrence)
grep -rc "pattern" . --include="*.adoc" | grep -v ':0$'  # match count per file
search with context — avoid opening the file
grep -rn -E 'git init|gh repo create' docs/ --include='*.adoc' -B2 -A2

Search codex by content — which files contain a command?

find all PowerShell files that use a specific cmdlet
find docs/modules/ROOT/examples/codex/powershell -type f -name "*.adoc" \
  -exec grep -l 'Get-Process\|Start-Process\|pipeline\|Where-Object' {} \;

Pattern: find -exec grep -l returns only filenames with matches — like grep -rl but with find’s `-type f -name filtering. Use \| for OR in grep basic regex. Swap the pattern for any cmdlet or keyword to locate coverage across the codex.

inventory a codex tool directory — count files per tier
find docs/modules/ROOT -name "powershell" -type d \
  -exec sh -c 'echo "$1: $(find "$1" -type f | wc -l) files"' _ {} \;
find orphaned examples (not included by any page)
for f in $(find docs/modules/ROOT/examples/codex/powershell -name "*.adoc" -type f); do
  base=$(basename "$f")
  dir_parent=$(basename $(dirname "$f"))
  grep -rq "$dir_parent/$base" docs/modules/ROOT/pages/codex/powershell/ \
    docs/modules/ROOT/examples/codex/powershell/*.adoc 2>/dev/null \
    || echo "ORPHAN: $f"
done

find → grep → open in nvim

find by path + content, open result in nvim
nvim $(find -path '*oauth*' -name '*.adoc' -type f \
  -exec grep -l 'timeout\|expire\|reconfig\|token' {} \;)

Command substitution $(…​) feeds all matches as arguments to nvim — opens every hit as a buffer. :bn/:bp to cycle, :ls to list. One file? Opens directly. Five files? All loaded, ready to navigate.

find by content across entire tree, open in nvim
nvim $(find docs/modules/ROOT -name '*.adoc' -type f \
  -exec grep -l 'token.*expire\|oauth.*refresh' {} \;)
open one at a time (sequential — -exec nvim per match)
find -path '*oauth*' -name '*.adoc' -type f \
  -exec grep -l 'timeout\|expire' {} \; \
  -exec nvim {} \;
Trailing \| in grep patterns matches empty string — every file matches. Always end with a term, not a pipe: 'timeout\|expire\|token' not 'timeout\|expire\|token\|'.

Trace Antora partial inclusion chains

who includes this partial? (one level up)
grep -rl 'commands/shell' docs/modules/ROOT/partials/
count all pages that include a partial
grep -rl 'quick-commands' docs/modules/ROOT | wc -l
full chain: partial → assembler → every page that uses it
file="commands/shell"
grep -rl "$file" docs/modules/ROOT/partials/ | while read f; do
  parent=$(basename "$f" .adoc)
  echo "$file -> $parent"
  grep -rl "$parent" docs/modules/ROOT/pages/ | while read p; do
    echo "  -> $(basename "$p")"
  done
done

Pattern: grep -rl finds which files contain the string. Chain two passes — first finds the assembler partial, second finds every page that includes it. Works for any partial in the Antora include hierarchy.

Multi-pattern file search — worklog partial discovery

brute force — one find per partial name
find docs/modules/ROOT -name "*urgent.adoc*" -type f
find docs/modules/ROOT -name "*morning.adoc*" -type f
consolidated — single find with regex (production approach)
find docs/modules/ROOT -type f -regextype posix-extended \
  -regex '.*(urgent|morning|work-chla|personal|education|infrastructure|quick-commands|related)\.adoc' \
  | sort

Pattern: -regextype posix-extended enables | alternation without escaping. One process, one sort — versus 8 separate finds. The sort deduplicates visually and groups by path.

pipeline alternative — find piped to grep
find docs/modules/ROOT -type f -name "*.adoc" \
  | grep -E 'urgent|morning|work-chla|personal|education|infrastructure|quick-commands|related'

Trade-off: the pipeline version is more readable but spawns two processes. The regex version is a single find — faster on large trees, same result.

Cross-repo literary term search — bibliotheca-wide discovery

When searching for a term across the entire _bibliotheca (multiple repos, mixed file types), these patterns escalate from narrow to broad.

1. Single repo — count matches per file
grep -rn --include='*.adoc' -c 'sanchuelo' . | grep -v ':0$'
2. Cross-repo — filenames only (all bibliotheca)
grep -rl --include='*.adoc' -i 'sanchuelo' ~/atelier/_bibliotheca/ | sort
3. Cross-repo with context — see the line in situ
grep -rn --include='*.adoc' -i -B1 -A1 'sanchuelo' ~/atelier/_bibliotheca/domus-captures/
4. Multi-filetype — .adoc + .txt (catches source texts)
grep -rl -i 'sanchuelo' ~/atelier/_bibliotheca/ --include='*.txt' --include='*.adoc' | sort
5. Null-safe find + xargs — handles spaces in paths
find ~/atelier/_bibliotheca/ -type f \( -name '*.adoc' -o -name '*.txt' \) -print0 \
  | xargs -0 grep -li 'sanchuelo' | sort
6. Open all hits directly in nvim
grep -rl -i 'sanchuelo' ~/atelier/_bibliotheca/ --include='*.adoc' --include='*.txt' | xargs nvim

Pattern escalation: #1 confirms the term exists and where. #2 expands to all repos. #3 shows context without opening files. #4 adds plain text sources (Quijote .txt originals). #5 is the safe version for automation. #6 opens everything for editing.

Trade-off: grep -r --include is faster for known file types. find | xargs grep is safer for paths with spaces and more extensible (add -name '*.md' etc.). For literary searches across the bibliotheca, #4 or #5 is usually the right starting point — the source texts are .txt, not .adoc.

Email thread analysis — extract people, dates, commitments, silence

who’s in the thread (@ mentions + From headers)
grep -P '(@\w+|^From:.*<)' comms.adoc
timeline — every date with context
grep -nP '\d{1,2}/\d{1,2}/\d{2,4}|20\d{2}-\d{2}-\d{2}' comms.adoc
commitments — who promised what
grep -niP '(I can |I will |I.ll |we will |we.ll )' comms.adoc
open questions and unknowns
grep -niP '(\?|need to confirm|need to validate|TBD|pending)' comms.adoc

comm — set difference (who hasn’t replied)

# All recipients
grep -oP '<\K[^>]+' comms.adoc | sort -u > /tmp/all-recipients

# All senders
grep -P '^From:' comms.adoc | grep -oP '<\K[^>]+' | sort -u > /tmp/replied

# Who's silent — follow-up targets
comm -23 /tmp/all-recipients /tmp/replied

comm -23 outputs lines only in file 1 (recipients not in senders). Requires sorted input. grep -oP '<\K[^>]+' uses PCRE lookbehind — match < but don’t include it, capture until >.

awk, sed, jq

awk — field extraction

print second field (whitespace-delimited)
awk '{print $2}' file.txt
custom delimiter — colon-separated (like /etc/passwd)
awk -F: '{print $1, $3}' /etc/passwd
extract JSON code blocks from AsciiDoc
awk '/\[source,json\]/{getline; if ($0 ~ /^----/) {p=1; next}} p && /^----/{p=0; next} p' file.adoc
field extraction with printf formatting
awk '{printf "%-30s %s\n", $1, $2}' file.txt

sed — stream editing

in-place replacement with verify-before/after
# Before
awk 'NR==73' /etc/ssh/sshd_config
# Change
sed -i '73s/#GSSAPIAuthentication no/GSSAPIAuthentication yes/' /etc/ssh/sshd_config
# After
awk 'NR==73' /etc/ssh/sshd_config
extract line range
sed -n '10,20p' file.txt

jq — JSON processing

extract nested fields
curl -s localhost:8080/stats | jq '.stats.total_files'
filter array by property
jq '.results[] | select(.category == "standards")' response.json
transform to TSV for spreadsheets
jq -r '.[] | [.title, .path] | @tsv' response.json | column -t -s $'\t'
GitHub API + jq — commit history by path
gh api "repos/EvanusModestus/domus-captures/commits?path=docs/&per_page=10" |
  jq -r '.[] | "\(.commit.author.date[:10]) \(.sha[:7]) \(.commit.message | split("\n")[0])"'

Shell Patterns

xargs — when the next command reads arguments, not stdin

Next command reads…​ Use

stdin (awk, grep, wc, sort)

pipe directly

arguments (stat, rm, cp, nvim, git add)

xargs

copy today’s files to backup — -I{} placeholder
mkdir -p /tmp/adoc-backup-$(date +%F) && \
  find . -name "*.adoc" -type f -newermt "$(date +%F)" | \
  xargs -I{} cp {} /tmp/adoc-backup-$(date +%F)/
parallel validation — -P4 runs 4 at a time
find .drafts -name "*.adoc" -type f | xargs -P4 -I{} asciidoctor -o /dev/null {}
null-delimited pipeline — safe for filenames with spaces
find . -name "*.adoc" -type f -print0 | xargs -0 wc -l

Process substitution — <(cmd) treats output as a file

compare tracker state: yesterday vs today
diff <(grep '|' partials/trackers/work/adhoc/carryover.adoc | head -20) \
     <(git show HEAD~1:partials/trackers/work/adhoc/carryover.adoc | grep '|' | head -20)
files on disk vs files in nav — drift detection
diff <(find docs/modules/ROOT/pages/projects/chla/mschapv2-migration -name "*.adoc" -type f | sort) \
     <(grep -oP 'mschapv2-migration/[^[]+\.adoc' docs/modules/ROOT/nav.adoc | sort)

Command substitution — embed output as arguments

open most recently modified file in nvim
nvim "$(find data/ -name '*.adoc' -type f -printf '%T@ %p\n' | sort -rn | awk 'NR==1{print $2}')"
line count across a project
wc -l $(find docs/modules/ROOT -path '*mschapv2*' -name '*.adoc' -type f)

Conditional execution — capture, test, act

open matching files only if they exist
files=$(find .drafts -name 'in*' -type f) && [ -n "$files" ] && nvim $files
open files that contain unchecked items
files=$(grep -rl '\[ \]' .drafts/*.adoc) && [ -n "$files" ] && nvim $files
guard with grep -q — only act if pattern matches
grep -q 'TODO\|FIXME\|\[ \]' "$file" && nvim "$file"

Pattern: $(capture)[ -n ] tests non-empty → && only proceeds if true. grep -q is the idempotent guard — run repeatedly, only opens when there’s work.

Decrypt and open — find .age, decrypt, nvim in one shot

files=$(find . -name "*tcp-clock*.age" -type f) && \
  [ -n "$files" ] && echo "$files" | xargs -I{} decrypt-file {} && \
  nvim $(echo "$files" | sed 's/\.age$//')

Pattern: find .age only (never tries plaintext), sed derives the decrypted path, guard prevents empty nvim. Change the glob to match any project.

tee_clean — color on screen, clean text in file

tee_clean() {
  tee >(sed 's/\x1b\[[0-9;]*m//g' > "$1")
}

# Color output on terminal, stripped in file
jq -C '.' data.json | tee_clean output.json
xq -C '.' data.xml | tee_clean output.json

# Wrap a whole block
{
  echo "=== Summary ==="
  jq -C '.[] | .name' data.json
} | tee_clean summary.txt

The >(cmd) is process substitution — tee writes to stdout AND to the subshell pipe. sed strips ANSI escape sequences (\x1b\[[0-9;]*m) before they hit the file.

Dependency check — verify toolchain in one shot

for cmd in asciidoctor asciidoctor-pdf pandoc rouge d2 mmdc age; do
  printf "%-20s %s\n" "$cmd" "$(command -v $cmd >/dev/null 2>&1 && echo 'OK' || echo 'MISSING')"
done

Pattern: command -v checks if binary exists on PATH. >/dev/null 2>&1 suppresses output — we only care about exit code. Swap the tool list for any project’s dependencies.

printf safety — dashes as data, not options

wrong — printf treats --- as invalid option
printf '---\n\n'
right — %s format string treats --- as data
printf '%s\n\n' '---'

Kill stuck SSH sessions

Find established SSH connections
lsof -i TCP -n -P | awk '/ssh.*ESTABLISHED/ {print $2, $9}'
Kill all stuck SSH sessions to a specific host
lsof -i TCP -n -P | awk '/ssh.*kvm-01.*ESTABLISHED/ {print $2}' | sort -u | xargs kill
Kill ALL stuck SSH sessions
lsof -i TCP -n -P | awk '/ssh.*ESTABLISHED/ {print $2}' | sort -u | xargs kill

lsof -i TCP -n -P lists all TCP connections. awk filters for SSH + ESTABLISHED, prints only the PID ($2). sort -u deduplicates (multiple file descriptors per process). xargs kill sends SIGTERM to each.

File Descriptors & Redirection

The three file descriptors

FD Name Purpose

0

stdin

input to the command

1

stdout

normal output (valid results)

2

stderr

error messages

Split stdout and stderr into separate files

find / -name "*.conf" 1>results.txt 2>errors.txt

Suppress errors — 2>/dev/null

find / -name "*.conf" 2>/dev/null

Merge stderr into stdout — 2>&1

command 2>&1 | grep "pattern"

This sends both stdout and stderr through the pipe. Without 2>&1, only stdout reaches grep — errors print to the terminal and bypass the pipeline.

Heredoc patterns

multi-line input to a command
cat <<'EOF'
Line 1
Line 2
EOF
heredoc commit messages (quotes prevent variable expansion)
git commit -m "$(cat <<'EOF'
feat: add new feature

Multi-line description here.
EOF
)"

API & curl/jq

domus-api — Documentation System REST API

start the API server
cd ~/atelier/_projects/personal/domus-api && uv run uvicorn domus_api.main:app --host 0.0.0.0 --port 8080
health check
curl -s localhost:8080/ | jq
full-text search
curl -s 'localhost:8080/search?q=mandiant' | jq
search — extract path, title, match count
curl -s 'localhost:8080/search?q=mandiant' | jq '.results[] | {path, title, match_count}'
list pages by category
curl -s 'localhost:8080/pages?category=standards' | jq
all antora.yml attributes
curl -s localhost:8080/attributes | jq

GitHub API

cross-repo search via GitHub API
gh search code "vault seal" --owner EvanusModestus --json repository,path,textMatches |
  jq '.[] | {repo: .repository.full_name, file: .path, match: .textMatches[].fragment}'
count .adoc files in a repo via API
gh api 'repos/EvanusModestus/domus-captures/git/trees/main?recursive=1' |
  jq '[.tree[] | select(.path | endswith(".adoc"))] | length'

Domus Workflows

Read content from terminal (meeting-ready)

today’s worklog
bat docs/modules/ROOT/pages/2026/04/WRKLOG-$(date +%Y-%m-%d).adoc
current priorities
bat docs/modules/ROOT/partials/trackers/work/priorities/current.adoc
carryover backlog
bat docs/modules/ROOT/partials/trackers/work/adhoc/carryover.adoc
any project summary
bat docs/modules/ROOT/partials/projects/mandiant-remediation/summary.adoc

Search and discovery

find all files related to a topic
grep -rl "MSCHAPv2" docs/modules/ROOT/ --include="*.adoc" | sort
search codex entries
grep -rn "pattern" docs/modules/ROOT/partials/codex/ --include="*.adoc" -B1 -A3
list all worklogs for a month
ls -1 docs/modules/ROOT/pages/2026/04/WRKLOG-*.adoc

Tracker aging — calculate days from origin

how many days since a carryover item started
echo $(( ($(date +%s) - $(date -d "2026-03-09" +%s)) / 86400 ))

Encrypted data access (d001)

view encrypted file without disk write
age --decrypt -i ~/.secrets/.metadata/keys/master.age.key \
  data/d001/projects/mandiant-remediation/findings-status-2026-04-16.adoc.age \
  | bat --language asciidoc
project encryption dashboard
for d in data/d001/projects/*/; do
  total=$(find "$d" -type f | wc -l)
  plain=$(find "$d" -type f ! -name '*.age' ! -name 'README.adoc' ! -name '.gitkeep' ! -name '*.py' | wc -l)
  printf "%-25s %s files  %s plaintext\n" "$(basename "$d")" "$total" "$plain"
done

ISE & Network Ops

ISE ERS API — endpoint CRUD

set credentials (session)
export ISE_HOST="{ise-ip}" ISE_USER="admin" ISE_PASS="$(gopass show -o ise/admin)"
list identity groups
curl -sk "https://$ISE_HOST:{ise-ers-port}/ers/config/identitygroup" \
  -H "Accept: application/json" -u "$ISE_USER:$ISE_PASS" | jq '.SearchResult.resources[].name'
check if endpoint exists by MAC
curl -sk "https://$ISE_HOST:{ise-ers-port}/ers/config/endpoint?filter=mac.EQ.AA:BB:CC:DD:EE:FF" \
  -H "Accept: application/json" -u "$ISE_USER:$ISE_PASS" | jq '.SearchResult.total'

Certificate inspection

view EAP-TLS client cert from local store
openssl x509 -in {cert-dir}/client.pem -text -noout | head -30
check cert expiry
openssl x509 -in {cert-dir}/client.pem -enddate -noout

Network diagnostics

check listening ports
ss -tlnp | grep -E ':{port-https}|:{port-ssh}|:{port-ldaps}'
test ISE connectivity
nc -zv {ise-ip} {ise-ers-port}
DNS resolution
dig {ise-hostname} +short

PowerShell (from zsh)

All PowerShell commands run inside pwsh -NoLogo -Command '…​' from zsh. Running them bare fails — zsh interprets $, |, () as shell syntax.

Process management

top 5 processes by memory
pwsh -NoLogo -Command 'Get-Process | Sort-Object WorkingSet64 -Descending |
  Select-Object -First 5 ProcessName, Id,
    @{N="MB";E={[math]::Round($_.WorkingSet64/1MB)}} | Format-Table'
stop/start Teams
pwsh -NoLogo -Command 'Get-Process | Where-Object {$_.ProcessName -like "*teams*"} | Stop-Process'
pwsh -NoLogo -Command 'Start-Process "ms-teams"'

Export to JSON (pipe to jq)

always use -NoLogo when piping pwsh output to zsh tools
pwsh -NoLogo -Command 'Get-Process | Sort-Object WorkingSet64 -Descending |
  Select-Object -First 5 ProcessName, Id,
    @{N="MB";E={[math]::Round($_.WorkingSet64/1MB)}} | ConvertTo-Json' | jq '.'
Never pipe Format-Table into ConvertTo-Json — it produces layout metadata, not data. Select-Object first, then ConvertTo-Json.

Wi-Fi management (netsh)

force fresh network scan
netsh wlan disconnect interface="Wi-Fi"
netsh wlan show networks mode=bssid
netsh wlan connect name="CHLA-Remote" interface="Wi-Fi"

SSH from PowerShell

connect to homelab from Windows terminal
ssh evan@modestus-razer.inside.domusdigitalis.dev

Security & Encryption

View encrypted files without writing to disk

pipe age decrypt to bat — nothing touches the filesystem
age --decrypt -i ~/.secrets/.metadata/keys/master.age.key \
  data/d001/projects/mandiant-remediation/findings-status-2026-04-16.adoc.age \
  | bat --language asciidoc --file-name "findings-status-2026-04-16.adoc"

Batch re-encrypt — brace expansion + loop

re-encrypt multiple project files
for f in data/d001/projects/mandiant-remediation/{findings-status,guest-acl-update,siem-report}-2026-04-16.adoc; do
  rm -f "${f}.age" && echo y | encrypt-file "$f"
done
Always rm -f the .age first. If you skip it, encrypt-file prompts about overwrite and may only delete the plaintext without re-encrypting.

Detect stale plaintext — files needing re-encryption

find plaintext newer than its .age counterpart
for f in data/d001/projects/*/*.adoc; do
  age="${f}.age"
  if [ -f "$f" ] && [ -f "$age" ]; then
    pt_mod=$(/usr/bin/stat -c'%Y' "$f")
    age_mod=$(/usr/bin/stat -c'%Y' "$age")
    [ "$pt_mod" -gt "$age_mod" ] && echo "STALE: $f"
  fi
done

Secure delete — shred for sensitive plaintext

shred -u data/d001/projects/mandiant-remediation/man-report.txt
On SSD/NVMe, shred is less effective (wear leveling), but better than rm which only removes the directory entry.

Pre-push audit — find all unencrypted project files

find data/d001/projects -type f ! -name '*.age' ! -name 'README.adoc' ! -name '.gitkeep' ! -name '*.py' | sort

System & Infrastructure

PipeWire audio validation

wpctl status                                    # PipeWire status
pactl list sinks short                          # list audio sinks
pw-play /usr/share/sounds/freedesktop/stereo/bell.oga  # test default sink
journalctl -b --grep='sof|cs35l56' --no-pager | tail -20  # kernel audio firmware
cat /proc/asound/cards                          # ALSA sound cards

gopass — personal document management

gopass-personal-docs    # interactive entry creation
gopass-query bills      # list recurring bills with totals
gopass-query storage    # list storage units with gate codes
gopass-query export bills  # export category to JSON

Makefile — daily workflow

make new-day      # create today's worklog + update attributes
make serve        # build + local server (port 8000)
make              # build only
make sync-nav     # sync worklog nav entries
make update-index # rebuild monthly index

Per-project file dashboard

per-project summary — total files vs unencrypted plaintext
for d in data/d001/projects/*/; do
  total=$(find "$d" -type f | wc -l)
  plain=$(find "$d" -type f ! -name '*.age' ! -name 'README.adoc' ! -name '.gitkeep' ! -name '*.py' | wc -l)
  echo "$(basename "$d") | ${total} files | ${plain} plaintext"
done