Decisions
One file per decision, numbered. The number is the identifier: it is what code cites, so it never changes and is never reused.
Each records the context that forced a choice, the alternatives weighed, and an outcome section when what shipped differed from what was decided. That last part is the point: a decision record whose outcome is never written back is how a document drifts away from the code it describes.
| # | Decision |
|---|---|
| 0001 | Read certificates through ext-openssl, keep the CLI as a fallback |
| 0002 | Parse the CMS in-package, by declared length |
| 0003 | Temporary files live outside the package, with guaranteed cleanup |
| 0004 | The seal is rendered in memory |
| 0005 | PHP 8.4 and Laravel 13 as the floor |
| 0006 | Sign by appending a revision, written in-package |
| 0007 | PEM as a second entry point onto one pipeline |
| 0008 | Exceptions name the fault that actually occurred |
| 0009 | Cross-reference streams |
| 0010 | Validation consumes the material signing writes |
| 0011 | The report carries signing time and certificate validity |
| 0012 | Certification signatures and DocMDP |
| 0013 | Signing into a field the document already carries |
| 0014 | Encrypted documents are refused, not signed badly |
| 0015 | Objects packed into object streams are read, and written back uncompressed |
| 0016 | Trust is the application's policy, and its verification is ours |
| 0017 | The seal goes where it was asked for |
| 0018 | Prefer the platform's own constructs: Laravel's helpers, and enums over class constants |
| 0019 | Validation reads what it writes, one level down |
| 0020 | Decode the filters documents actually use |
| 0021 | Locking fields, and honouring the locks already there |
| 0022 | The archive timestamp is a chain, not a state |
| 0023 | A seal that can be transparent, and say what the caller wants |
| 0024 | Revocation is evaluated, not counted |
| 0025 | What signing does to PDF/A, measured |
| 0026 | The verification tools are instruments, and nothing skips |
| 0027 | The transport is a seam, so the profiles can be gated |
| 0028 | The seal carries its own colour space, built rather than vendored |
| 0029 | The identity a Brazilian signer is known by |
| 0030 | Signing a document that is encrypted |
| 0031 | Certification is verified by a reader that enforces it |
| 0032 | What signing does to PDF/UA, measured |
| 0033 | The seal honours the page's rotation |
| 0034 | Signing takes ownership of the document |
| 0035 | The audit trail is opt-in, and its context is an allowlist |
| 0036 | The signed artefacts are reproducible, and their coherence is a gate |
| 0037 | What we write, against the specification's own grammar |
| 0038 | The envelope is versioned, so material sealed by signet-pdf still opens |
| 0039 | The core lives in signet-pdf, and this package is the Laravel adapter |
Nothing is currently proposed and unbuilt. The four that were, 0009, 0010, 0012 and 0013, all shipped in 2.2, and each carries the measurement that decided its shape rather than only the shape.
0012 carried a caveat for two releases, and it is closed. Its verification was deliberately incomplete, because pdfsig does not surface /DocMDP and no reader the project had would say whether a certification is enforced. 0031 found one that does, pyHanko, and made it a gate: a certified document modified beyond its level is now reported as violating its policy on every run.
Rules that break the product when violated are not decisions and do not live here. They are in the invariants.