# FEEDBACK — mgf-django

> Paper-tracking file for issues, friction, and requests against
> this sibling. Consumer projects (PlasmaMapper, inthewords,
> vm-vmanager-app, figrecovery, and any future adopter) file PAPER-NN
> entries here.
>
> **Where to file what:**
>
> - **mgf-django-specific** → file HERE.
> - **Federation-wide** (cross-sibling patterns, standards
>   proposals) → file in
>   [mgf-common/FEEDBACK.md](https://codeberg.org/magogi-admin/mgf-common/src/branch/main/FEEDBACK.md).
>
> **Numbering convention:** paper numbers (`PAPER-NN`) are
> local to this repo. When a paper cross-references a
> federation-wide paper, the federation number appears in the
> metadata table as a cross-reference row.
>
> **Discipline:** see
> [mgf-standard/docs/standards/DOCUMENTATION.md](https://codeberg.org/magogi-admin/mgf-standard/src/branch/main/docs/standards/DOCUMENTATION.md)
> §FEEDBACK (rules FB-01..FB-04, DOC-13).

---

## §1 Process

1. **File freely.** Any consumer hitting friction MUST file
   a PAPER-NN under §2. Don't wait for permission; the
   maintainer triages.
2. **Status flips** through `OPEN` → `SHIPPED` / `DEFERRED` /
   `WONTFIX` / `MOVED` as the paper resolves. A `SHIPPED` row
   carries a commit-SHA reference + release-version reference.
3. **Renumbering** never happens within this repo — papers
   keep their PAPER-NN forever (per FB-01).

---

## §2 Open feedback (active)

#### `PAPER-01` — `LOGGING` dictConfig recipe is minimal; first-time wiring leaves Django's own loggers silent

| Field | Value |
|---|---|
| Status | ✅ SHIPPED |
| Severity | 🟢 Nice-to-have |
| Submitter | inthewords (this commit) |
| Submitted | 2026-05-18 |
| Decision | accept: replace the minimal recipe with a production-shaped LOGGING reference in both the recipe doc and the module docstring |
| Decided on | 2026-07-10 |
| Scheduled for | — |
| Shipped in | next release (this commit, branch `feedback/queue-sweep-2026-07-10`, 2026-07-10) |

**Concern.** The recipe at `docs/recipes/django.md` lines 25–37
(mirrored verbatim in `src/mgf/django/__init__.py` module
docstring) shows the bare-minimum `LOGGING` dictConfig — three
nested keys: one formatter, one handler, one root entry. It is a
correct invocation of the public `JsonFormatter` factory shape,
but a Django consumer copy-pasting it into a real project
discovers four omissions on first run:

1. **`disable_existing_loggers` is not set.** Django defaults
   this key to `True` when omitted, which means every named
   logger Django ships (`django.request`, `django.security`,
   `django.db.backends`, etc.) goes silent. The consumer's first
   indication is "where did my server's request log lines go?"
2. **No per-logger overrides for the Django-shipped loggers.**
   Typical production needs `django.request` at WARNING (404s
   are noise) and `django.security` at INFO (auth failures are
   signal). The recipe's `root: INFO` doesn't shape this.
3. **No dev/prod formatter split.** Production wants
   `JsonFormatter` so log aggregators can parse fields; dev wants
   a colour-coded human-readable formatter so the developer can
   read the console. The recipe shows one formatter (JSON);
   adopters now have to invent the conditional themselves.
4. **No sample of what `JsonFormatter` actually emits.** The
   adopter wires the formatter, runs the server, sees a line of
   JSON in the console, and now has to reverse-engineer the
   field shape to write a Grafana / Loki / Datadog log-parser
   query. The shape IS deterministic and documented elsewhere,
   but a one-line comment showing a sample emitted record would
   close the loop on the recipe page.

**Why it matters.** Every new Django adopter of mgf-django hits
these in the first hour. The library's `__init__.py` docstring
says "That's the entire integration" right after the snippet —
which is true for `JsonFormatter` correctness, but false for
"my Django service has working logging." The most-cited
adoption-friction question for any Django logging library is
"why did my Django loggers go silent?", and the recipe walks
right past it.

**Concrete evidence.** A real Django production `LOGGING` block
that actually works looks like the one inthewords ships in
`config/settings/base.py` (80 lines): `disable_existing_loggers:
False`, two formatters (dev vs prod), five named loggers, three
handlers. The mgf-django recipe is a 7-line subset that survives
contact with `python manage.py runserver` but not with a real
project's logging needs. A consumer following the recipe
literally ends up debugging missing logs before they debug their
code.

The thinness is doubly load-bearing because the **`mgf.django`
module docstring** (visible to anyone who does `help(mgf.django)`
or reads the package source) shows the same minimal snippet —
the docs and the code-resident example reinforce each other, so
the consumer doesn't get a second-source nudge.

**Suggested shape.** Replace the recipe snippet (and the mirrored
`__init__.py` docstring block) with a production-shaped reference:

```python
# config/settings.py — Django LOGGING with mgf.django.JsonFormatter
import os

_use_json = os.environ.get('LOG_FORMAT', 'json' if not DEBUG else 'dev') == 'json'

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,           # KEEP Django's loggers
    'formatters': {
        'json': {'()': 'mgf.django.JsonFormatter'},
        'dev':  {'format': '[%(asctime)s] %(levelname)-7s %(name)s %(message)s'},
    },
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
            'formatter': 'json' if _use_json else 'dev',
        },
    },
    'root': {'handlers': ['console'], 'level': 'INFO'},
    'loggers': {
        'django.request':     {'handlers': ['console'], 'level': 'WARNING', 'propagate': False},
        'django.security':    {'handlers': ['console'], 'level': 'INFO',    'propagate': False},
        'django.db.backends': {'handlers': ['console'], 'level': 'WARNING', 'propagate': False},
    },
}

# Example emitted JSON line (prod):
# {"ts": "2026-05-18T10:00:00.123Z", "level": "INFO", "logger": "myapp.views",
#  "msg": "request handled", "request_id": "...", "trace_id": "..."}

MGF_COMMON_APP_NAME = "myapp"
MGF_COMMON_APP_VERSION = "1.0.0"
```

50 lines that "just work" beats 7 lines that "show the idea but
need filling in." The reference covers the three things a Django
adopter needs to know on day one: how to keep Django's own
loggers alive, how to split dev/prod formatters, and what the
emitted JSON looks like.

Optional follow-on: a sentence under "What you get → 4.
JsonFormatter" pointing at `mgf.common.observability.JsonFormatter`
field reference (`{ts, level, logger, msg, ...}`) so the adopter
knows exactly what fields their log-parser query targets without
reading source.

**Decision rationale.** Accepted. Verified on 2026-07-10: the
recipe at `docs/recipes/django.md` and the mirrored
`src/mgf/django/__init__.py` docstring both still showed the 7-line
minimal `LOGGING` (no `disable_existing_loggers`, no per-logger
overrides, no dev/prod split, no emitted-record sample) — all four
omissions the paper lists were live.

**Resolution.** SHIPPED 2026-07-10 (queue sweep, branch
`feedback/queue-sweep-2026-07-10`). Both surfaces now carry the
production-shaped reference from the paper's suggested shape:
`disable_existing_loggers: False` (with an inline comment explaining
why it is load-bearing), a `json`/`dev` formatter split keyed off
`LOG_FORMAT`/`DEBUG`, named-logger overrides for `django.request`
(WARNING) / `django.security` (INFO) / `django.db.backends`
(WARNING), and a sample emitted JSON record. The sample's field set
was generated from the real formatter, not invented:
`uv run python -c "...JsonFormatter().format(LogRecord(...))"` emits
`{"ts", "level", "level_no", "logger", "msg", "app", "app_version",
"lang", "host", "module", "func", "line", "thread", "process",
"schema_version"}` — the recipe shows exactly those fields, with a
pointer to `mgf.common.observability.JsonFormatter` for the full
reference (the paper's optional follow-on). Gates green: ruff check,
ruff format --check, mypy, pytest.

**Retrospective.** Recipe snippets that double as the module
docstring are the consumer's only two sources; when both show the
same minimal shape there is no second-source nudge. Production-shaped
references beat idea-shaped ones for integration recipes.

---

## §3 Reviewer's meta-feedback

### From vm-vmanager-app (CLI/desktop consumer of mgf-common) — 2026-05-18

Cross-cutting observation derived from vm-vmanager-app's `0.34 → 0.38`
catch-up to mgf-common ([commit `212808f`](https://codeberg.org/magogi-admin/vm-vmanager-app/commit/212808f),
2026-05-18) and the federation-contract-conformance audit
([commit `61cf070`](https://codeberg.org/magogi-admin/vm-vmanager-app/commit/61cf070)).
I am NOT an mgf-django consumer — vm-vmanager-app has no web surface
and likely never will. This is a federation-design observation
for the maintainer.

**The observation.** Auditing vm-vmanager-app (a CLI/desktop application
with no Django / ORM / web-request shape) against mgf-common's
v2.10 standards corpus, the rules namespace that cleanly carved
out was **DEP-\*** (DEPLOYMENT.md). Every DEP rule carries an
explicit `service` applicability tag in
[`mgf-standard/docs/standards/DEPLOYMENT.md`](https://codeberg.org/magogi-admin/mgf-standard/src/branch/main/docs/standards/DEPLOYMENT.md)
that let vm-vmanager-app mark them ❌ N/A as a single-row entry in
[`docs/inprogress/MGF_STANDARDS_CONFORMANCE.md`](https://codeberg.org/magogi-admin/vm-vmanager-app/src/branch/main/docs/inprogress/MGF_STANDARDS_CONFORMANCE.md)
rather than paragraph-rationale per rule. This was the single
biggest time-saver in the audit.

**Implication for mgf-django.** As mgf-django layers its own
standards on top of mgf-common (the `health_view` planned for
v0.5+, the feature-flag context-processor coming from the C-1
`mgf.common.flags` adoption in 0.35, etc.), **tag each new rule
with applicability**:

- `web` — applies to projects that import this sibling.
- `service` — applies to long-running server processes.
- `universal` — applies to every consumer regardless of shape.

This is the same observation I filed against mgf-fastapi; it
applies federation-wide. mgf-common's DEP-* tagging proved the
pattern works. The same convention applied to every sibling
standards doc scales linearly with the federation, and
consumer-side catch-up tooling can then auto-filter
non-applicable rules. Cost on the sibling-author side: one
column in the rule table.

- **Resolution:** 2026-07-10 queue sweep — triaged. mgf-django
  currently publishes **no rule table of its own**
  (`docs/standards/README.md` §"Project-specific standards":
  "None"), so there is nothing to retro-tag today. The convention is
  ACCEPTED as a design constraint and recorded in
  `docs/standards/README.md`: any future mgf-django-authored rule
  table MUST carry a `web` / `service` / `universal` applicability
  column, per mgf-common's DEP-* precedent. Same disposition as the
  twin observation in mgf-fastapi's queue (resolved the same day).
- **Status:** ACCEPTED (standing convention; no rule table to
  retro-tag yet)

---

## §4 How consumers submit feedback

1. **Open a Codeberg issue** at
   <https://codeberg.org/magogi-admin/mgf-django/issues> if
   you have a quick question. Maintainer triages.
2. **For a structured pain point**: file a PAPER-NN here as a PR
   that adds the entry to §2.
3. **For AI-agent-driven consumer sessions**: see your project's
   `docs/CLAUDE.md` auto-block (managed by `mgf-common catch-up`)
   — the `feedback-discipline` section spells out where to file
   what.

---

## §5 Cross-references

- [mgf-common/FEEDBACK.md](https://codeberg.org/magogi-admin/mgf-common/src/branch/main/FEEDBACK.md)
  — federation-wide PAPERs.
- [mgf-standard/docs/standards/DOCUMENTATION.md](https://codeberg.org/magogi-admin/mgf-standard/src/branch/main/docs/standards/DOCUMENTATION.md)
  — FEEDBACK discipline rules.
